Built-in compare on discriminated unions in f# - f#

In answering this question, I discovered the following behaviour of compare on discriminated unions.
type T = A | B | C | D
compare A B (* val it : int = -1 *)
compare A C (* val it : int = -2 *)
compare A D (* val it : int = -3 *)
I was surprised by this.
Can I rely on compare measuring the "distance" between constructors like this?
The spec says (p. 154) about the generated compareTo:
If T is a union type, invoke Microsoft.FSharp.Core.Operators.compare first on the index of the union cases for the two values, and then on each corresponding field pair of x and y for the data carried by the union case. Return the first non-zero result.
From that, I'd expect compare on type T to always give one of -1,0,1 since that's how compare behaves on numeric types. (Right?)

The quote from the specification says that the generated comparison will first compare the tags (that is essentially the index of the constructors), but I'm not sure if this gives you any useful information - because if the union carries some value, you will not know whether the number is distance between the constructors, or the result of the comparison of the contained values. For example:
type Tricky() =
interface System.IComparable with
override x.CompareTo(b) = -2
type DU =
| A of Tricky
| B
| C
// Returns -2 because of the distance between constructors
compare (A (Tricky())) C
// Returns -2 because of the comparison on `Tricky` objects
compare (A (Tricky())) (A(Tricky()))
If you wanted to rely on the ability to get the distance between constructors, it might be safer to use enumerations:
type DU =
| A = 1
| B = 2
| C = 3
Then you can get the distance by converting the values to integers using (int DU.A) - (int DU.C).

Related

Discriminated Union with Integer Values in F#

I'm trying to compose an F# type that would have the following signature:
type Foo = (Distance * Event * Course)
So that you would create a Foo like this:
let bar = (25, Freestyle, LCM)
Now the second two parts (event and course) are easy–I'm sure that distance is also, I just don't know it yet–I just use a discriminated union.
Let's say that the only valid values for distance are [25;50;100], what is the best way to construct the Distance type?
I assume the goal is to have easy access to a real integer value, but restrict it to only a set number of cases.
#Petr's suggestion would work fine, you would just convert the enum value to int.
Another option is to calculate the value in a method on a DU type:
type Distance =
TwentyFive | Fifty | Hundred
member this.ToInt() =
match this with
| TwentyFive -> 25
| Fifty -> 50
| Hundred -> 100
or if you want stronger syntax support, a single-case active pattern might be nice:
type Event = Freestyle | Backstroke
type Distance = TwentyFive | Fifty | Hundred
let (|IntDistance|) d =
match d with
| TwentyFive -> 25
| Fifty -> 50
| Hundred -> 100
let race = (Fifty, Freestyle)
let (IntDistance(dist), evt) = race
printfn "Race info: %d %A" dist evt
match race with
| IntDistance(dist), Freestyle -> ...
| IntDistance(dist), Backstroke -> ...
You can use .NET enums:
type Distance = TwentyFive=25 | Fifty=50 | Hundred=100
For pattern matching you must use qualified name though: Distance.Fifty

Is it possible to create a discriminated union via a unit of measure tag in F#?

Is it possible to create a discriminated union type via a unit of measurement tag in F#?
I want to write sth. like the following:
type DomainObject =
| Pixel of int
| ScaledPixel of int
| Centimeter of float
| Unset
let var1 = 10<px> // should equal: let var1 = Pixel(10)
let var2 = 0<us> // should equal: let var2 = Unset
let process sth =
match sth with
| Pixel(p) -> ...
| Centimeter(c) -> ...
// etc.
With NumericLiterals such things are possible. But then one can only use a small amount of Literals like Neil P. showed.
As I said in the comment, the simple answer is no.
In a way, you are trying to misuse one F# feature (units of measure) to emulate a feature that might exist in other languages (suffix operators), which is probably a bad thing to do in the first place, because (even if it was possible), the resulting code would be quite confusing.
If you simply want to reverse the order of the arguments so that the number comes before the unit name, you can use the piping operator and write:
let var1 = 10 |> Pixel
let var2 = Unset
This essentially gives you a way to write "suffix operators", but using standard F# idioms.
I don't think that this special combination is possible but you can go with smart constructors if you like:
module Domain =
[<Measure>] type px
[<Measure>] type spx
[<Measure>] type cm
// ...
type DomainObject =
| Pixel of float<px>
| ScaledPixel of float<spx>
| Centimeter of float<cm>
| Unset
let inline pixel f = Pixel <| float f * 1.0<px>
let inline scaledPixel f = ScaledPixel <| float f * 1.0<spx>
let unset = Unset
// ...
let var1 = pixel 10
let var2 = unset
let process sth =
match sth with
| Pixel(p) -> ...
| Centimeter(c) -> ...
// etc.
I think this is reasonable close - if you want you can make the constructors private and add active-patterns (to reenable pattern-matching) or accessors to fully encapsulate the implementation-details.
If you get fancy you can even add (+), (-), ...
PS: the inline is to get the functions working with all kinds of numeric values ;)
PPS: I played a bit and the problem is indeed (as mentioned in the link you gave - that you can only have a very limited set of "suffixes" - namely Q, R, Z, I, N, and G) - for example this kindof works:
module NumericLiteralQ =
open Domain
let inline FromZero() = Pixel 0.0<px>
let inline FromOne() = Pixel 1.0<px>
let inline FromString (s:string) =
System.Double.Parse s * 1.0<px> |> Pixel
let inline FromInt32 (n:int) =
1.0<px> * float n |> Pixel
let inline FromInt64 (n:int64) =
1.0<px> * float n |> Pixel
but I think it's very uggly to write
let p = 5Q
instead of
let p = pixel 5
or
let p = 5 |> pixel

Basic f# error - pattern matching is implying the wrong type

The following code takes 2 parameters. the first is a list of triples: The triple (d,m,y) is meant to represent a date.
the second is an integer which is a month
The code is meant to count the number of occurrences of dates with that month in the list
p.s. I guess this probably looks like a homework question - it's not. It's from a course I did earlier in the year in ML and I'm trying to redo all the exercises in f#. So it's only for my benefit
let rec number_in_month (dates : (int * int * int) list, month) =
match dates with
| [] -> 0
| (_,y,_) when month = y -> 1 + number_in_month(dates.Tail, month)
| _ -> number_in_month(dates.Tail, month)
but it gives the error :
This expression was expected to have type
(int * int * int) list but here has type
'a * 'b * 'c
any idea what I'm doing wrong?
Your second pattern match is trying to match a single date (_,y,_) but it is being matched against your list of dates. Try matching using (_,y,_)::_ instead.
More idiomatic would be to match using (_,y,_)::tail and to use tail instead of dates.Tail later in the expression.
The code can also be tightened up (including the fix MarkP suggested). Note the use of type inference so that the type of dates does not need to be passed
let rec number_in_month dates month =
match dates with
| [] -> 0
| (_,y,_)::tail ->
( number_in_month tail month) + (if y = month then 1 else 0)
let data = [(1,2,3);(1,2,3);(1,5,7);(1,9,2);(1,9,2);(1,9,2)]
number_in_month data 5
number_in_month data 2
http://www.tryfsharp.org/create/bradgonesurfing/datefinder.fsx

Is there an arbitrary precision float in F#? Something like BigFloat?

Is there a data type in F# that lets me calculate a float to an arbitrary/large number of decimal places? Something like the floating point equivalent of BigInt.
I would like do something like
myLargeFloat = 1.0/7.0
printfn "%12.500f" myLargeFloat // get the recurring cycle "0.142857142857142857...<500 digits long>"
I was using the BigInt to get the precision by multiplying the numerator with a bigint like so.
myLargeFloat = (bigint.Pow(10I,500)/7I)
Is there a better way of doing this?
BigRational in the F# Powerpack is defined like this:
[<CustomEquality; CustomComparison>]
[<StructuredFormatDisplay("{StructuredDisplayString}N")>]
type BigRational =
| Z of BigInteger
| Q of BigRationalLarge
Where a BigRationalLarge is defined as:
[<CustomEquality; CustomComparison>]
type BigRationalLarge =
| Q of BigInteger * BigInteger
To Print a BigInt with 1000 precision do something like this:
let factorial n = Seq.fold ( * ) 1I [1I .. n]
printf "Factorial of 1000 is %A" (factorial 1000I)
Taken from here.
Looking at the BigRationalLarge type here:
There are a number of ways to convert it to a different type to print:
static member ToDouble(n:BigRational) =
match n with
| Z z -> ToDoubleI z
| Q q -> BigRationalLarge.ToDouble q
static member ToBigInt(n:BigRational) =
match n with
| Z z -> z
| Q q -> BigRationalLarge.integer q
static member ToInt32(n:BigRational) =
match n with
| Z z -> ToInt32I(z)
| Q q -> ToInt32I(BigRationalLarge.integer q )
The conversion to a double looks like this:
static member ToDouble (Q(p,q)) =
ToDoubleI p / ToDoubleI q
The default way of printing it as a numerator and denominator combination:
override n.ToString() =
let (Q(p,q)) = n
if q.IsOne then p.ToString()
else p.ToString() + "/" + q.ToString()
None of that really helps us get more precision. There is no way to print it while specifying the number of decimal places to print.
So to answer your question:
You could make a function that prints the values you want, using the two BigInt parts of a BigRational or you could write an entirely new type to do this for you, but there isn't anything like that right now.
There is a BigRational type in the F# PowerPack. See also http://tomasp.net/blog/powerpack-numeric.aspx
If you truly require arbitrary-precision floats, you'll have to use #mydogisbox's method. If you just need something with better precision than float (i.e., System.Double) you can try using the decimal type; it's an alias for System.Decimal, which is the .NET implementation of 128-bit binary-coded decimal (BCD). It's much more precise than float but much slower too (like 10-20x).

Does F# treat parameter matching differently when there is only one input parameter?

The function matching is based on the definition of the file in F#:
let f2 x y = x + y
let value5 = f2 10 20
let value = f2(10, 20) <-- Error
let f3 (x, y) = x + y
let value6 = f3(10, 20)
let value = f3 10 20 <-- Error
However, I can use in both ways with one parameter with F#:
let f n = n + 10
let value3 = f 10
let value4 = f(10)
Why is this? Does F# treat parameter matching differently when there is only one input parameter?
As ashays correctly explains, the two ways of declaring functions are different. You can see that by looking at the type signature. Here is an F# interactive session:
> let f1 (x, y) = x + y;;
val f1 : int * int -> int
> let f2 x y = x + y;;
val f2 : int -> int -> int
The first function takes a tuple of type int * int and returns int. When calling it, you need to specify the tuple (which is just a single value):
// Using tuple directly as the argument
f1 (1, 2)
// .. or by declaring tuple value first
let tup = (1, 2)
f1 tup
The type of the second function is int -> int -> int, which is the same thing as int -> (int -> int). This means that it is a function that takes int and returns a function that takes int and returns int. This form is called curried form and it allows you to use partial function application as demonstrated by ashays. In fact, the call:
f2 1 2
// Could be written as:
(f2 1) 2
My suspection is that this has something to do with tuples and currying. Basically, a tuple of one item becomes a singular item again, however in our other two cases we have the following:
The first case (f2) is actually a function that takes a single value (x) and returns a value that takes another single function. Here we can see the use of currying from f2 to add10
let add10 = f2 10
let myVal = add10 20
We get an error with the tuple because we have not defined it in such a way as to receive a tuple. In the second example, we have a similar issue, where we defined the function to take a tuple of two values, and it knows how to process those values, but we have passed it two values now instead of the one (a tuple) that it was expecting, and thus we receive an error.
Once again, in the last case, we have a tuple of a single item and so f x and f(x) are effectively the same thing.
I could be wrong in my reasoning, but I believe that's why you're getting your errors.

Resources