Reputation: 32192
I have the code to implement some geometric operations between primitives
type point = double * double
type shape =
| Point of point
| Line of point * point
| Vector of point
| Circle of point * double
with
member this.ToString = function
| Point (x,y) -> sprintf "(%f; %f)" x y
| Vector (x,y) -> sprintf "(%f; %f)" x y
| Line ((x0,y0),(x1,y1)) -> sprintf "(%f; %f)->(%f; %f)" x0 y0 x1 y1
| Circle ((x0,y0),radius) -> sprintf "(%f; %f)r%f" x0 y0 radius
let inline (-) (Point (x0,y0)) (Point (x1,y1)) = Vector (x0-x1,y0-y1)
let inline (+) (Point (x0,y0)) (Vector (x1,y1)) = Point (x0+x1,y0+y1)
And the compiler says that the pattern match on the operators is not exhaustive though this is only a warning. How can I correctly implement operators only between specific sub type of the DU without the compiler complaining?
Upvotes: 3
Views: 842
Reputation: 2920
I would do the following:
type PointT = double * double
type Shape =
| Point of PointT
| Line of PointT * PointT
| Vector of PointT
| Circle of PointT * double
with
member this.ToString = function
| Point (x,y) -> sprintf "(%f; %f)" x y
| Vector (x,y) -> sprintf "(%f; %f)" x y
| Line ((x0,y0),(x1,y1)) -> sprintf "(%f; %f)->(%f; %f)" x0 y0 x1 y1
| Circle ((x0,y0),radius) -> sprintf "(%f; %f)r%f" x0 y0 radius
let inline (-) (p0 : Shape) (p1 : Shape) : Shape option =
match p0, p1 with
| Point(x0, y0), Point(x1, y1) -> Some(Vector(x0 - x1, y0 - y1))
| _ -> None
let inline (+) (p0 : Shape) (p1 : Shape) : Shape option =
match p0, p1 with
| Point(x0, y0), Vector(x1, y1) -> Some(Point(x0 + x1, y0 + y1))
| _ -> None
Upvotes: 1
Reputation: 25516
The basic problem is that at compile time, the compiler does not know if which specific instance of shape you have chosen to create. As a result, any restriction must be done at run time, or by imposing additional constraints on the type. I think the most elegant solution with run time checking would be something like
type shape = ...
static member (-) (a,b) =
match (a,b) with
|Point(c,d),Point(e,f) -> ...
|Point(c,d),Vector(e,f) -> ...
| _ -> failwith "Can't add these shapes"
Alternatively, you could change shape to have point and vector as subtypes of a different DU as follows
type addable = |Point of point |Vector of point
and then modify shape
accordingly.
Upvotes: 1
Reputation: 55195
As a side note, you've got another problem, which is that ToString
should match on this
, but right now matches on an anonymous argument (instead of having type unit -> string
, it's shape -> string
. Also, it should be declared with override
, not member
(which would also have pointed out that the signature is wrong).
Upvotes: 3
Reputation: 47914
Operators are typically defined as static members:
type shape =
...
static member (-) (x, y) =
match x, y with
| Point (x0,y0), Point (x1,y1) -> Vector (x0-x1,y0-y1)
| Point (x0,y0), Vector (x1,y1) -> Point (x0+x1,y0+y1)
| _ -> failwith "invalid arguments"
A few notes about your attempt:
Upvotes: 4