How can I access the named fields of a discriminated union's member?
Example:
type Point = | Point of x : int * y : int
let p = Point(3, 1)
// how to access x-value or y-value of p here?
In general, unions with named fields work just like any other union type: You would access the fields via match:
let x, y =
match p with
| Point (x1, y1) -> x1, y1
The F# documentation also mentions a way of matching only some named parameters. In your case, this means you can write:
let xOnly =
match p with
| Point (x = x1) -> x1
If all you have is a single case, see the answer by #p.s.w.g. The code in that answer is general for all discriminated unions. For singleton unions with named fields, you can use the special syntax shown above and write:
let Point(x = myX) = p
This binds the value of field x to myX.
PS as per the comments: Why can you not read out the fields right away, by doing p.x? You can think of a discriminated union as a small object hierarchy (and use it such, see the discriminated union documentation: "You can often use a discriminated union as a simpler alternative to a small object hierarchy"). Consider the following DU:
type Shape = | Circle of r: float | Square of float
You can view Shape as the superclass. Circle and Square are two derived classes, each with a single float property. Each instance of Circle or Square that you create will be upcast to be a Shape.
With that, it becomes clear why you can't read out the fields immediately: you first need to establish which of the derived classes you are looking at, only after the cast to the right subclass you can read out the fields.
This object hierarchy view matches very closely to how DUs are handled internally by F#: If you look at the DU type in reflection, you will see two nested types that have the same name as your union cases:
> typeof<Shape>.GetNestedTypes()
|> Seq.iter (fun t ->
let p = t.GetProperties()
let s =
p
|> Array.map (fun p -> sprintf "%s: %s" p.Name p.PropertyType.Name)
|> String.concat "; "
printfn "Nested type %s: %i Properties %s" t.Name p.Length s
);;
Nested type Tags: 0 Properties
Nested type Circle: 4 Properties r: Double; Tag: Int32; IsCircle: Boolean; IsSquare: Boolean
Nested type Square: 4 Properties Item: Double; Tag: Int32; IsCircle: Boolean; IsSquare: Boolean
The actual data lives in properties of the subclass. For Circle, we used named fields, you see the property r. For Square, we have data in the Item property (or Item1, Item2 if there were multiple arguments). The rest are compiler generated: the numeric Tag field that will be used to quickly distinguish between the subclasses, and two bool properties for subclass checks.
The superclass itself only has compiler-generated properties:
> typeof<Shape>.GetProperties()
|> Seq.iter (fun p -> printfn "Property %s" p.Name);;
Property Tag
Property IsCircle
Property IsSquare
For single-case discriminated unions like your example, you don't need to use a match-with expression. You could just do this:
let (Point (x, y)) = p
printf "%i" x // 3
Or to just get x and ignore y:
let (Point (x, _)) = p
printf "%i" x // 3
Related
How can I call F# functions by specifying the parameter names in the call site?
I've tried the following:
let add x y =
x + y
add (x = 10) (y = 10) // How to specify the name x and y when calling add?
But it gives this error:
error FS0039: The value or constructor 'x' is not defined.
You can't invoke let-bound functions with named arguments. It's allowed only for methods in classes
Named arguments are allowed only for methods, not for let-bound functions, function values, or lambda expressions.
Documentation
Technically you can declare static class and use method from it, but I think it's wrong. Just wrong. Don't do it
[<AbstractClass; Sealed>]
type MathOperations =
static member Add (x, y) = x + y
open type MathOperations
[<EntryPoint>]
let main argv =
Add(x = 3, y = 4)
|> printfn "%d"
0
This issue confused me too in the beginning. Functions and methods are not alike.
Functions are curried by default to support partial application. They don't support named argument calls.
Methods support named arguments using a single tuple for all parameters.
(EDIT after Bent Tranberg's comment) Methods also support curried declaration member _.Add x y = x + y and even mixed style declaration member _.Add3 (x: int, y: int) (z: int) = x + y + z but these methods cannot be called using named arguments o.Add3 (y=2, x=1) 3 💥
In JavaScript, named arguments can be simulated using an object literal as argument. Let's try do the same in F#, using tuple or record:
1. Tuple: Method arguments are provided all at once with a tuple. Can we use a tuple as function parameter and call the function with named arguments? No ❌
let add (x, y) = x + y
add (x = 1, y = 2) // 💥
// ~ Error FS0039: The value or constructor 'x' is not defined
2. Anonymous record: not possible due to actual limitation in anonymous record deconstruction ❌
let add {| X = x; Y = y |} = x + y
// ~~ Error FS0010: Unexpected symbol '{|' in pattern
3. Named record: ⚠️
type AddParam = { x: int; y: int }
let add { x = x; y = y } = x + y
add { x = 1; y = 2 }
This way, we are able to name the arguments and choose their order ({ y = 2; x = 1 } but we loose the partial application. So it's not idiomatic→ should be avoided, unless in specific cases.
4. Single-case DU: 👌
If we care only about the argument naming but not about the argument re-ordering, we can use discriminated unions, especially single-case DU:
type XParam = X of int
type YParam = Y of int
let add (X x) (Y y) = x + y
add (X 1) (Y 2)
This way, the arguments appeared as named and partial application is preserved.
--
EDIT
☝ I don't recommend creating single-case DU just to simulate named arguments ! It's the other way around: when we have single-case DU in our domain model, we know that they will bring their semantic to document the code and help reasoning about the code, in this case more or less like named arguments.
You have to understand function calling in F#, which is different from traditional imperative languages like C#.
let f x y = x + y // defines a function with this signature:
val f : x:int -> y:int -> int
// this function is full or partially applicable:
let g = f 4 // partial application
val g : (int -> int) // a new function that evaluates f 4 y
g 10
val it : int = 14
In traditional languages functions have a single set of arguments. In F# you express such traditional functions with multiple arguments into a function with a tuple argument:
let f (x, y) = x + y
val f : x:int * y:int -> int
// partial application is no longer possible, since the arguments have been packed into a single tuple
Such traditional tuple-argument functions do not allow calls with named arguments:
f (x=3, y=5) // interpreted as = test expressions
F# language design is sound here, and (x=3, y=5) does not express the desired tuple.
F# has named arguments since a while (this was added in the last years sometime). This is limited to member functions however. Once you translate your function into a member it works:
type A() =
static member f (x,y) = x + y
A.f(y=3, x=4) // yes, this works!
I have a discriminated union like this:
type A = |B | C of int*A
I have to pattern match like this (the parenthesis appear to be needed):
match x with
| B -> printfn "B"
| C (i,a) -> printfn "%A, %A" i a
Is there a way to instead match like this with something like an active pattern:
match x with
| B -> printfn "B"
| C i a -> printfn "%A, %A" i a
And if not how come F# is designed such that this matching with curried arguments doesn't work and it instead forces you to use a tuple?
Edit: This was inspired by the F# list in which you can use h::t without any tupling or anything like that. And the source code is like:
type List<'T> =
| ([]) : 'T list
| (::) : Head: 'T * Tail: 'T list -> 'T list
I think examining the definitions of a curried function and an active pattern will make this clear for you.
Curried function:
A function which takes multiple parameters but which allows you to pass them in one at a time in order to return a function which does the same thing but takes one fewer parameters. Example:
let add a b = a + b
//val add : a:int -> b:int -> int
let add5 = add 5
//val add5 : (int -> int)
Active Pattern:
A way of applying pattern matching where the matching can be done using parsing or other complex logic. Takes one parameter and returns the result of the parsing. So input -> single return parameter.
//Example taken from https://fsharpforfunandprofit.com/posts/convenience-active-patterns/
let (|Int|_|) str =
match System.Int32.TryParse(str) with
| (true,int) -> Some(int)
| _ -> None
val ( |Int|_| ) : str:string -> int option
Since the whole point of currying a function is to be able to partially apply the function, the concept simply makes no sense when applied to the result of an active pattern.
Put another way, the result of an active pattern can't be "curried" because you can only curry functions and the result of an active pattern is data which is not a function. In your example, 'C (i,a)' is defining the return type of the Active Pattern case, not a function call.
You cannot have whitespace as delimiter between bound patterns, because neither union cases nor active patterns support this. Syntax as per the F# spec:
6.9.8 Evaluating Union Case
Case(e1,…,en)
7.2.3 Active Patterns
(|CaseName|) arg1 ... argn inp
(|CaseName|_|) arg1 ... argn inp
So it's necessarily one tupled argument for a union case; and n+1 arguments for the banana function, of which n arguments are parameters. Only the last argument binds to the pattern. Consider:
type X = B | C
let (|C|) a b = C (a, b)
let i = 42
match C with
| B -> printfn "B"
| C i a -> printfn "%A, %A" i a // prints 42, (42, C)
The case C in your discriminated union has a value of a tuple type (int * A).
The (i,a) part of your pattern matching isn't a parameter, it's matching the i to the int part and the a to the A part.
You could equally match with C x and x would hold a tuple of (int * A).
Is there a quick and simple way to convert an entire list of strings into floats or integers
and add them together similar to this in F#?
foreach(string s in list)
{
sum += int.Parse(s);
}
If you want to aim for minimal number of characters, then you can simplify the solution posted by Ganesh to something like this:
let sum = list |> Seq.sumBy int
This does pretty much the same thing - the int function is a generic conversion that converts anything to an integer (and it works on strings too). The sumBy function is a combination of map and sum that first projects all elements to a numeric value and then sums the results.
Something like this should have the same effect:
let sum = list |> Seq.map System.Int32.Parse |> Seq.sum
F# doesn't seem to support referring to the method on int so I had to use System.Int32 instead.
In F# the type seq is an alias for the .NET IEnumerable, so this code works on arrays, lists etc.
Note the use of Parse in "point-free" style - a function without its argument can be used directly as an argument to another function that expects that type. In this case Seq.map has this type:
('a -> 'b) -> seq<'a> -> seq<'b>
And since System.Int32.Parse has type string -> int, Seq.map System.Int32.Parse has type seq<string> -> seq<int>.
Technically, there are at least 3 different approaches:
1) The Seq.sum or sumBy approach described in the other answers is the canonical way of getting the sum in F#:
let sum = Seq.sumBy int list
2) For instructional purposes, it may be interesting to see how closely one can simulate C# behavior in F#; for instance, using a reference cell type:
let inline (+=) x y = x := !x + y
let sum = ref 0
for s in list do sum += int s
3) Same idea as 2), but using a byref pointer type:
let inline (+=) (x:_ byref) y = x <- x + y
let mutable sum = 0
for s in list do &sum += int s
I am currently porting some code from Java to F# that deals with multidimensional functions. It supports variable dimension, so in the original implementation each point is represented as an array of doubles. The critical function of the code is an optimisation routine, that basically generates a sequence of points based on some criteria, evaluates a given function at these points and looks for a maximum. This works for any dimension. The operations I need are:
check the dimension of a point
create a new point with the same dimension of a given point
set (in procedural or functional sense) a given coordinate of a point
In F# I could obviously also use arrays in the same way. I was wandering though if there is a better way. If the dimension was fixed in advance, the obvious choice would be to use tuples. Is it possible to use tuples in this dynamic setting though?
No, tuples will be fixed by dimension. Also note that .NET tuples are boxed. If you are operating on large collections of points with small dimension (such as arrays of 2d points), using structs may help.
If you really want to push the F#/.NET advantage over Java, have a look at generics. Writing code with generics allows to write code that works for any dimension, and use different representations for different dimensions (say structs for 1-3 dimensions, and vectors for larger dimensions):
let op<'T where 'T :> IVector> (x: 'T) =
...
This is only relevant though if you are willing to go a long way to get the absolutely best performance and generality. Most projects do not need that, stick with the simplest thing that works.
For the fun of it, here is an extended example of how to utilize generics and F# inlining:
open System.Numerics
type IVector<'T,'V> =
abstract member Item : int -> 'T with get
abstract member Length : int
abstract member Update : int * 'T -> 'V
let lift<'T,'V when 'V :> IVector<'T,'V>> f (v: 'V) : 'V =
if v.Length = 0 then v else
let mutable r = v.Update(0, f v.[0])
for i in 1 .. v.Length - 1 do
r <- r.Update(i, f v.[i])
r
let inline norm (v: IVector<_,_>) =
let sq i =
let x = v.[i]
x * x
Seq.sum (Seq.init v.Length sq)
let inline normalize (v: 'V) : 'V =
let n = norm v
lift (fun x -> x / n) v
[<Struct>]
type Vector2D<'T>(x: 'T, y: 'T) =
member this.X = x
member this.Y = y
interface IVector<'T,Vector2D<'T>> with
member this.Item
with get (i: int) =
match i with
| 0 -> x
| _ -> y
member this.Length = 2
member this.Update(i: int, v: 'T) =
match i with
| 0 -> Vector2D(v, y)
| _ -> Vector2D(x, v)
override this.ToString() =
System.String.Format("{0}, {1}", x, y)
[<Sealed>]
type Vector<'T>(x: 'T []) =
interface IVector<'T,Vector<'T>> with
member this.Item with get (i: int) = x.[i]
member this.Length = x.Length
member this.Update(i: int, v: 'T) =
let a = Array.copy x
a.[i] <- v
Vector(a)
override this.ToString() =
x
|> Seq.map (fun e -> e.ToString())
|> String.concat ", "
[<Struct>]
type C(c: Complex) =
member this.Complex = c
static member Zero = C(Complex(0., 0.))
static member ( + ) (a: C, b: C) = C(a.Complex + b.Complex)
static member ( * ) (a: C, b: C) = C(a.Complex * b.Complex)
static member ( / ) (a: C, b: C) = C(a.Complex / b.Complex)
override this.ToString() = string c
let v1 = Vector2D(10., 30.)
normalize v1
|> printfn "%O"
let v2 = Vector2D(C(Complex(1.25, 0.8)), C(Complex(0.5, -1.)))
normalize v2
|> printfn "%O"
let v3 = Vector([| 10.; 30.; 50.|])
normalize v3
|> printfn "%O"
Note that norm and normalize are fairly general, they cope with specialized 2D vectors and generalized N-dimensional vectors, and with different component types such as complex numbers (you can define your own). The use of generics and F# inlining ensure that while general, these algorithms perform well for the special cases, using compact representations. This is where F# and .NET generics shine compared to Java, where you are obliged to create specialized copies of your code to get decent performance.
How do I match union cases dynamically in F# when there are value declarations?
Non working code:
let myShape = Shape.Square
expect myShape Shape.Circle
type Shape =
| Circle of int
| Square of int
| Rectangle of ( int * int )
let expect someShape someUnionCase =
if not ( someShape = someUnionCase )
then failwith ( sprintf "Expected shape %A. Found shape %A" someShape someUnionCase )
let myShape = Shape.Square
expect myShape Shape.Circle // Here I want to compare the value types, not the values
If my union cases did not declare values, this works using instantiation samples (which is not what I want):
let myShape = Shape.Square
expect myShape Shape.Circle
type Shape =
| Circle
| Square
| Rectangle
let expect someShape someUnionCase =
if not ( someShape = someUnionCase )
then failwith ( sprintf "Expected shape %A. Found shape %A" someShape someUnionCase )
let myShape = Shape.Square
expect myShape Shape.Circle // Comparing values instead of types
Interestingly, this can be done very easily in C#, but the F# compiler will not allow you to call the functions - which seems odd.
The spec says that a discriminated union will have (section 8.5.3):
One CLI instance property u.Tag for each case C that fetches or
computes an integer tag corresponding to the case.
So we can write your expect function in C# trivially
public bool expect (Shape expected, Shape actual)
{
expected.Tag == actual.Tag;
}
It is an interesting question as to why this can't be done in F# code, the spec doesn't appear to give a good reason why.
When you call the expect function in your example with e.g. Shape.Square as an argument, you're actually passing it a function that takes the arguments of the union case and builds a value.
Analyzing functions dynamically is quite difficult, but you could instead pass it concrete values (like Shape.Square(0)) and check that their shape is the same (ignore the numeric arguments). This can be done using F# reflection. The FSharpValue.GetUnionFields function returns the name of the case of an object, together with obj[] of all the arguments (which you can ignore):
open Microsoft.FSharp.Reflection
let expect (someShape:'T) (someUnionCase:'T) =
if not (FSharpType.IsUnion(typeof<'T>)) then
failwith "Not a union!"
else
let info1, _ = FSharpValue.GetUnionFields(someShape, typeof<'T>)
let info2, _ = FSharpValue.GetUnionFields(someUnionCase, typeof<'T>)
if not (info1.Name = info2.Name) then
failwithf "Expected shape %A. Found shape %A" info1.Name info2.Name
If you now compare Square with Circle, the function throws, but if you compare two Squares, it works (even if the values are different):
let myShape = Shape.Square(10)
expect myShape (Shape.Circle(0)) // Throws
expect myShape (Shape.Square(0)) // Fine
If you wanted to avoid creating concrete values, you could also use F# quotations and write something like expect <# Shape.Square #> myValue. That's a bit more complex, but maybe nicer. Some examples of quotation processing can be found here.
I use the same pattern to implement type checking in HLVM. For example, when indexing into an array I check that the type of the expression is an array ignoring the element type. But I don't use reflection as the other answers have suggested. I just do something like this:
let eqCase = function
| Circle _, Circle _
| Square _, Square _
| Rectangle _, Rectangle _ -> true
| _ -> false
Usually in a more specific form like this:
let isCircle = function
| Circle _ -> true
| _ -> false
You could also do:
let (|ACircle|ASquare|ARectangle|) = function
| Circle _ -> ACircle
| Square _ -> ASquare
| Rectangle _ -> ARectangle
If you do decide to go the reflection route and performance is an issue (reflection is unbelievably slow) then use the precomputed forms:
let tagOfShape =
Reflection.FSharpValue.PreComputeUnionTagReader typeof<Shape>
This is over 60× faster than direct reflection.
NOTE this has a caveat. See UPDATE below.
It appears that union cases are implemented as nested classes of the union type (type name: FSI_0006+Shape+Square). So given a union type instance, checking the type of the instance by obj.GetType() is sufficient.
let expect (someShape:'T) (someUnionCase:'T) =
if (someShape.GetType() <> someUnionCase.GetType()) then failwith "type not compatible"
type Shape =
| Circle of int
| Square of int
| Rectangle of ( int * int )
let myShape = Shape.Square 12
printfn "myShape.GetType(): %A" (myShape.GetType())
expect myShape (Shape.Circle 5)
This outputs:
myShape.GetType(): FSI_0006+Shape+Square
System.Exception: type not compatible
at Microsoft.FSharp.Core.Operators.FailWith[T](String message)
> at FSI_0006.expect[T](T someShape, T someUnionCase)
at <StartupCode$FSI_0006>.$FSI_0006.main#()
Stopped due to error
I just don't know if this approach is considered implementation dependent, i.e., some platform/runtime implements this differently such that the types of two different union case objects are the same.
UPDATE
OK I found the above doesn't work for union type with cases that don't take parameters. In that case, the implementation of the cases are different and .GetType() always gives the union type's declaring type. The below code demonstrates this:
type Foo = A|B|C
type Bar = X|Y|Z of int
let getType (x:obj) = x.GetType()
let p (x:obj) = printfn "%A" x
A |> getType |> p
B |> getType |> p
C |> getType |> p
X |> getType |> p
Y |> getType |> p
Z 7 |> getType |> p
This gives:
FSI_0004+Foo
FSI_0004+Foo
FSI_0004+Foo
FSI_0004+Bar+_X
FSI_0004+Bar+_Y
FSI_0004+Bar+Z
The more general alternative, as mentioned in another answer, would be to convert the case instances into tags:
open Microsoft.FSharp.Reflection
// more general solution but slower due to reflection
let obj2Tag<'t> (x:obj) =
FSharpValue.GetUnionFields(x, typeof<'t>) |> fst |> (fun (i: UnionCaseInfo) -> i.Tag)
[A;B;C;A] |> List.map obj2Tag<Foo> |> p
[X;Y;Z 2; Z 3; X] |> List.map obj2Tag<Bar> |> p
This gives:
[0; 1; 2; 0]
[0; 1; 2; 2; 0]
This should be considerably slower if operated on large amount of objects, as it's heavily depend on reflection.