How to define operators for discriminated unions in f# - f#

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?

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:
union cases are not types, so they can't be used to define method overloads
functions can't be overloaded

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).

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.

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

Related

Incomplete structured construct at or before this point in pattern matching

So, I'm doing an assignment where I'm supposed to write a function that prints an image based on some a type, figure, which I have defined.
I'm to use this library and it's functions with my own .fsx file, which should then be compiled and able to create images, based on a descriptive "figure"-type ;
https://github.com/diku-dk/img-util-fs
My .fsx code looks like this;
type point = int * int
type color = ImgUtil.color
type figure =
| Circle of point * int * color
| Rectangle of point * point * color
| Mix of figure * figure
let rec colorAt (x,y) figure =
match figure with
| Circle ((cx,cy), r, col) ->
if (x-cx)*(x-cx)+(y-cy)*(y-cy) <= r*r
then Some col else None
| Rectangle ((x0,y0), (x1,y1), col) ->
if x0 <=x && x <= x1 && y0 <= y && y <= y1
then Some col else None
| Mix (f1, f2) ->
match (colorAt (x,y) f1, colorAt (x,y) f2) with
|(None , c) -> c
|(c, None) -> c
|(Some c1, Some c2) ->
let (a1 ,r1 ,g1 ,b1) = ImgUtil.fromColor c1
let (a2 ,r2 ,g2 ,b2) = ImgUtil.fromColor c2
in Some(ImgUtil.fromArgb ((a1+a2)/2, (r1+r2)/2,
(g1+g2)/2, (b1+b2)/2))
let figTest : figure =
Circle ((50,50), 45, ImgUtil.fromRgb(255,0,0))
Rectangle ((40,40), (90,110) ImgUtil.fromRgb (0,0,255))
let makePicture (name:string * x:figure * b:int * h:int) : unit =
let C = ImgUtil.mk b h
for i = 0 to h
do ImgUtil.setLine (ImgUtil.fromRgb(128,128,128)) (0,i) (b,i) C
for n = (0,0) to (b-1,h-1) do
match ImgUtil.getPixel n C with colorAt n x
| None -> (128,128,128)
| Some col -> colorAt n x
do imgUtil.toPngFile ("%A" name) C
do makePicture ("figTest" figTest 101 151)
But when I try to compile the library and my .fsx file I get the error
"8io.fsx(44.13): error FS0010: Incomplete structured construct at or before this point in pattern matching. Expected '->' or other token"
I'm fairly new to coding, and my code might not be usable, but it's the only compiling error I get, so I hope it's salvageable
I think the problem you're asking about is caused by this construct:
match ImgUtil.getPixel n C with colorAt n x
| None -> (128,128,128)
| Some col -> colorAt n x
The problem here is that colorAt n x appears unexpectedly between the with and the first |. A typical match expression should look more like this:
match ImgUtil.getPixel n C with
| None -> (128,128,128)
| Some col -> colorAt n x
Note: I haven't examined your code for correctness. This only addresses the specific syntactical issue identified by the compiler.

Represent finite coordinates as an F# type

I'm learning F# by implementing a board game engine. In accordance with the principle that invalid states should not be representable, I want to create a type which represents (x, y) coordinates (with x and y integers) where x and y must satisfy 0 <= x <= n and 0 <= y <= m. Creating an instance that does not satisfy those inequalities shouldn't compile. Is this possible?
I don't think compile time assurances on values like this are possible.
I would handle this with a private constructor and the Result or Option type depending whether I wanted to propagate error information.
type Position =
private {
X: int
Y: int
}
static member TryNew(x, y) =
if x >= 0 && x <= 10 then
if y >= 0 && y <=10 then
Ok {
X = x
Y = y
}
else
Error $"Supplied y ({y}) must be between 0 and 10"
else
Error $"Supplied x ({x}) must be between 0 and 10"
module Position =
let moveX1 pos =
Position.TryNew(pos.X + 1, pos.Y)
This does create the issue where Results are now everywhere in your code but they don't have to be visible or cause you a lot of typing. This problem is precisely what computation expression libraries e.g. FsToolkit.ErrorHandling are designed to eliminate.
let example =
result {
let! start = Position.TryNew(0,0)
let! next = start |> moveX1
}
There's no way to do this that takes integers as input, but it can be done with a type that only provides integers as output:
type XCoord = X0 | X1 | X2 with
member this.Int =
match this with
| X0 -> 0
| X1 -> 1
| X2 -> 2
static member (-)(xa : XCoord, xb: XCoord) =
xa.Int - xb.Int
type YCoord = Y0 | Y1 | Y2 with
member this.Int =
match this with
| Y0 -> 0
| Y1 -> 1
| Y2 -> 2
static member (-)(ya : YCoord, yb: YCoord) =
ya.Int - yb.Int
type Point = MkPoint of (XCoord * YCoord) with
member this.Ints =
let (MkPoint (x, y)) = this
x.Int, y.Int
static member (-)((MkPoint (ax, ay)), (MkPoint (bx, by))) =
ax - bx, ay - by
let ptA = MkPoint (X0, Y1)
let ptB = MkPoint (X2, Y0)
printfn "%A" ptA.Ints
printfn "%A" ptB.Ints
printfn "%A" (ptA - ptB)
I think this would be pretty clunky to use in practice, but it might work, depending on exactly what you want to do with it. I guess it's a case of "careful what you ask for". 😀

F# unable to catch DivideByZeroException

I atempt to catch an exception when dividing by 0 is performed but, no mater the implementation, code shows nothing of substance, always claiming that the result is "infinity" (meaning, from what I get, that it just performed the division and ignored everything else)
What is the reason for this and how to remedy it?
open System
type instruction =
| ADD
| SUB
| MUL
| SQR
| DIV
| PUSH of float
type stack = float list
exception BLEDNY_PROGRAM of (instruction * stack)
exception DivideByZeroException
let intInstr (x, y) =
match x, y with
| ADD, a::b::ys -> (b + a) :: ys : stack
| SUB, a::b::ys -> (b-a)::ys
| MUL, a::b::ys -> (b*a)::ys
| SQR, a::ys -> (a * a)::ys
| DIV, a::b::ys -> try (b/a)::ys with | :? System.DivideByZeroException -> (printf "BÅ‚Ä…d: dzielenie przez zero"; ys)
| PUSH x, ys -> x::ys
| _ , _ -> raise (BLEDNY_PROGRAM(x, y));
let intpProg(is) =
let rec iPS = function
| ([],x::xs) -> x
| (i::is, xs) -> iPS(is, intInstr(i, xs))
iPS(is,[])
let il3 = [PUSH 3.0; PUSH 0.0; DIV];
let e = intpProg(il3)
printfn "%A" e
A float in F# is a 64-bit IEEE 754 double-precision number. They have well-defined values for ±zero, ±infinity, and NaN.
For all floating point divisions by zero (except decimal), a DivideByZeroException is not thrown, but rather, the type's special representation is used.
> let ``+∞``, ``-∞`` = 1.0 / 0.0, -1.0 / 0.0;;
val ( -∞ ) : float = -infinity
val ( +∞ ) : float = infinity
In your example, dividing by zero would give you Double.PositiveInfinity.
Integer values (int, long, uint, etc.,) all throw a divide by zero as you'd expect.

F# Polynomial Derivator

I'm writing a program that takes a polynomial and returns its derivative. The polynomial is passed as predefined type "poly", which is a list of tuples in which the first element is a float representing a coefficient, and the second is an integer representing the degree of that term. So a poly p = [(2.0, 3);(1.5,2);(3.2;1)] would represent 2x^3 + 1.5x^2 + 3.2x^1. My code is as follows:
let rec diff (p:poly):poly =
match p with
| [] -> raise EmptyList
| [a]-> (fst a * snd a, snd a - 1)
| x::xs -> ((fst x * snd x), (snd x - 1)) :: diff xs
The error I'm getting tells me that the program expects the function to return a type poly, but here has the type 'a * 'b. I don't see why thats the case, when in my base case I return a tuple and in all other situations I'm appending onto an accumulating list. I've played around with the brackets, to no avail. Why is my code tossing this error?
All input is appreciated on the matter.
you said it yourself: in the base case you are returning a tuple not a list - so the inference thinks this is what you want
Just change it into:
let rec diff (p:poly):poly =
match p with
| [] -> raise EmptyList
| [a]-> [fst a * snd a, snd a - 1]
| x::xs -> ((fst x * snd x), (snd x - 1)) :: diff xs
and it should be fine (just replace the (..) with [..] ;) )
remember: :: will cons a new head onto a list
there are a few issues with float vs. int there so I would suggest this (using recursion):
type Poly = (float*int) list
let test : Poly = [(2.0, 3);(1.5,2);(3.2,1);(1.0,0)]
let rec diff (p:Poly):Poly =
match p with
| [] -> []
| x::xs -> (fst x * float (snd x), snd x - 1) :: diff xs
which is really just this:
let diff : Poly -> Poly =
List.map (fun x -> fst x * float (snd x), snd x - 1)
and can look a lot nicer without fst and snd:
let diff : Poly -> Poly =
List.map (fun (a,p) -> a * float p, p - 1)

Accumulator generator in F#

In my quest to learn more F#, I tried to implement an "accumulator generator" as described by Paul Graham here. My best solution so far is completely dynamically typed:
open System
let acc (init:obj) : obj->obj=
let state = ref init
fun (x:obj) ->
if (!state).GetType() = typeof<Int32>
&& x.GetType() = typeof<Int32> then
state := (Convert.ToInt32(!state) + Convert.ToInt32(x)) :> obj
else
state := (Convert.ToDouble(!state) + Convert.ToDouble(x)) :> obj
!state
do
let x : obj -> obj = acc 1 // the type annotation is necessary here
(x 5) |> ignore
printfn "%A" (x 2) // prints "8"
printfn "%A" (x 2.3) // prints "10.3"
I have three questions:
If I remove the type annotation for x, the code fails to compile because the compiler infers type int -> obj for x - although acc is annotated to return an obj->obj. Why is that and can I avoid it?
Any ideas to improve this dynamically typed version?
Is it possible to implement this with proper static types? Maybe with member constraints? (It is possible in Haskell, but not in OCaml, AFAIK)
In my quest to learn more F#, I tried to implement an "accumulator generator" as described by Paul Graham here.
This problem requires the existence of an unspecified numeric tower. Lisp happens to have one and it happens to be adequate for Paul Graham's examples because this problem was specifically designed to make Lisp look artificially good.
You can implement a numeric tower in F# either using a union type (like type number = Int of int | Float of float) or by boxing everything. The following solution uses the latter approach:
let add (x: obj) (y: obj) =
match x, y with
| (:? int as m), (:? int as n) -> box(m+n)
| (:? int as n), (:? float as x)
| (:? float as x), (:? int as n) -> box(x + float n)
| (:? float as x), (:? float as y) -> box(x + y)
| _ -> failwith "Run-time type error"
let acc x =
let x = ref x
fun (y: obj) ->
x := add !x y
!x
let x : obj -> _ = acc(box 1)
do x(box 5)
do acc(box 3)
do printfn "%A" (x(box 2.3))
However, numeric towers are virtually useless in the real world. Unless you are very careful, trying to learn from these kinds of borked challenges will do you more harm than good. You should leave asking yourself why we do not want a numeric tower, do not want to box and do not want run-time type promotion?
Why didn't we just write:
let x = 1
let x = x + 5
ignore(3)
let x = float x + 2.3
We know the type of x at every step. Every number is stored unboxed. We know that this code will never produce a run-time type error...
I agree with Jon that this is quite artificial example and it is not a good starting point for learning F#. However, you can use static member constraints to get reasonably close without dynamic casts and reflection. If you mark it as inline and add convert both of the parameters using float:
let inline acc x =
let x = ref (float x)
fun y ->
x := (float y) + !x
!x
You'll get a function with the following type:
val inline acc :
^a -> ( ^b -> float)
when ^a : (static member op_Explicit : ^a -> float) and
^b : (static member op_Explicit : ^b -> float)
The function takes any two arguments that can be explicitly converted to float. The only limitation compared to the LISP version (I guess) is that it always returns float (as the most universal numeric type available). You can write something like:
> acc 1 2;; // For two integers, it returns float
val it : float = 3.0
> acc 1 2.1;; // integer + float
val it : float = 3.1
> acc 1 "31";; // It even works with strings!
val it : float = 32.0
It's definitely not possible to implement this with proper static types. You say you can in Haskell, but I don't believe you.
The problem with trying to do this with static typing is in adding two different numbers of possibly different types while preserving the type of the left-hand side. As Jon Harrop says this is possible with a union type. Once you've defined the union type and a corresponding addition operation which works as mentioned, the actual accumulator is very simple. My implementation:
module MyTest
type Numeric =
| NInt of int
| NFloat of float
member this.Add(other : Numeric) : Numeric =
match this with
| NInt x ->
match other with
| NInt y -> NInt (x + y)
| NFloat y -> NInt (x + (int y))
| NFloat x ->
match other with
| NInt y -> NFloat (x + (float y))
| NFloat y -> NFloat (x + y)
override this.ToString() =
match this with
| NInt x -> x.ToString()
| NFloat x -> x.ToString()
let foo (n : Numeric) =
let acc = ref n
fun i ->
acc := (!acc).Add(i)
!acc
let f = foo (NFloat 1.1)
(2 |> NInt |> f).ToString() |> printfn "%s"

Resources