F# - constructing nested types - f#

I guess this is pretty basic F# question:
Types are:
type Id1 =
| Id1 of int
type Id2 =
| Id2 of string
type Id =
| Id1
| Id2
type Child = {
Id : Id;
Smth : string list
}
type Node =
| Child of Child
| Compos of Node * Node
where Node and Child should represent replacement for Composite OOP design pattern.
The problem is that I cannot instantiate types in this way:
let i1 : Child = {Id = Id1(1); Smth = []} //Id1 value is not a function and cannot be applied
let i2 : Child = {Id = Id1(1); Smth = []} //same
let i3 : Node = Compos(i1, i2) //Expression expected Node but has Child
where compiler errors are given in the comments.

Your definition of Id has the same semantics as the following:
type T = int | string
Such type, which is just a mix of two other types, is commonly referred to as "non-discriminated union". To be fair, there are languages that support non-discriminated unions (e.g. TypeScript), but F# is not one of them. F# is part of the ML family of languages, which support discriminated unions. The "discriminated" part there means that the parts of the union need to be given a distinguishing property, a "discriminator", which is more commonly called "constructor". For example:
type T = X of int | Y of string
Here, X and Y are constructors of type T. They are used when constructing values to tell which variant is being constructed:
let t = X 42
And they are used during pattern matching to tell which variant is expected:
let f t = match t with
| X n -> printfn "it's a number: %d" n
| Y s -> printfn "it's a string: %s" s
You actually have one of those in your own code - Node, - so it baffles me a bit why you made this mistake with Id, but not with Node.
If you want to construct values of Id the way you do in the definition of i1 and i2 - i.e. Id1(1), - then you need to make Id a discriminated union with one of the constructors named Id1 and taking an int as parameter. From the rest of your code I can guess that the other constructor should be Id2 and take a string:
type Id = Id1 of int | Id2 of string
Now, an interesting thing to note is that, while my example type T above wouldn't compile, your type Id compiles just fine. Why is that?
The reason is that int and string have the wrong capitalization (union case identifiers must be uppercase), but Id1 and Id2 are fine in that respect. When you define your type as type Id = Id1 | Id2, that is perfectly legal, but those Id1 and Id2 have no relation to the previously defined types Id1 and Id2. They just happen to have the same name, and having the same name as previous definitions is allowed in F#. It is called "shadowing".
Your type Id ended up having two constructors, Id1 and Id2, both of which have no parameters. This is why the compiler complains when you're trying to pass 1 as parameter to Id1 as you write Id1(1): "Id1 is not a function and cannot be applied"

Related

Discriminated Union label to string

given the following Discriminated Union:
type A = B of string | C of int
How can I get the constructor B name?
A.B.ToString()
// would return something like:
val it : string = "FSI_0045+it#109-19"
// when I desire
val it : string = "B"
for example with this type it works:
type D = E | F
D.E.ToString();;
val it : string = "E"
I normally get the string name of an instance of the DU with
let stringFromDU (x: 'a) =
match FSharpValue.GetUnionFields(x, typeof<'a>) with
| case, _ -> case.Name
But in this case, I do not have an instance, I just want to serialize the label name.
If you enable the latest language version, e.g. by passing --langversion:preview to FSI or setting
<PropertyGroup>
<LangVersion>preview</LangVersion>
</PropertyGroup>
in your .fsproj, the following will work:
type A = B of int
let n = nameof A.B
Note: with F# 5 this will be supported out of the box :-)
You're using FSharpValue from FSharp.Reflection namespace in your example. Note that there's another class in that library for handling scenarios where you want to work with types only, FSharpType.
let cases = FSharpType.GetUnionCases(typeof<A>)
Outside of unions, it also provides helpers for other operations on F# native types.

Pattern matching casting types

I am a newbie in F# and have been following guides to try to make a piece of code work but it hasn't.
I create types of single and coop sports through inheritance.
Then I use pattern matching to know the type and, if it is a coop sport, get also the number of players. Then rank each accordingly.
However, I have been getting errors. I followed Microsoft examples on this and I don't really understand the errors. I don't have a functional programming background.
type Sport (name: string) =
member x.Name = name
type Individual(name: string) =
inherit Sport(name)
type Team(name: string, numberOfPlayers : int) =
inherit Sport(name)
member x.numberOfPlayers = numberOfPlayers
let MK = new Individual("Combate Mortal")
let SF = new Individual("Lutadores de Rua")
let Tk = new Individual("Tekken Chupa")
let MvC = new Team("Marvel Contra Capcom", 3)
let Dbz = new Team("Bolas do Dragao", 3)
let interpretSport (sport:string) (players:int) =
match sport with
| "Combate Mortal" -> printfn "Rank1"
| "Lutadores de Rua" -> printfn "Rank2"
| "Tekken Chupa" -> printfn "Rank3"
| "Bolas do Dragao" -> printfn "Rank4. No of players: %d " players
| "Marvel Contra Capcom" -> printfn "Rank5. No of players: %d" players
| _ -> printfn "not a sport in our list..."
let matchSport (sport:Sport) =
match sport with
| :? Individual -> interpretSport(sport.Name)
| :? Team as teamSport -> interpretSport(teamSport.Name,teamSport.numberOfPlayers)
| _ -> printfn "not a sport"
matchSport(MK)
matchSport(SF)
matchSport(Tk)
matchSport(MvC)
matchSport(Dbz)
1st error when calling function with more than 1 argument:
2nd error when printing:
The question has already been answered, but because the asker says he is a newby in F#, maybe it's worth to iterate a little.
To begin, you define a function with two parameters:
let interpreteSport (sport:string) (player:int) =
In F#, there is no notion of optional parameters in the same sense that they exist in C#, so if you declare a function with two parameters, and you want to invoke it, and get its return value, you must supply all the parameters you put in its definition.
So in the first branch of your match expression, when you write:
:? Individual -> interpretSport(sport.Name)
you are making an error, passing only one parameter to a function that takes two.
But wait! Why the compiler don't alert you with an error saying you are calling a function with one parameter when it expects two?
Because it turns out that what you write, even if it does not call the interpreteSport function as you believed, it's a perfect valid expression in F#.
What it returns is an expression called "partially applied function", that is, a function that has received its first parameter, and is waiting for another one.
If you assign the result of such an expression to a value, let's say:
let parzFun = interpretSport sport.Name
you can then pass this value around in your code and, when you are ready to supply the missing parameter, evaluate it like this:
let result = parzFun 1
That's what the compiler is telling you when it talks about 'int -> unit': function signatures in F# are given in this form:
a -> b -> c -> d -> retval, where a, b, c, d etc. are the types of the parameters, and retVal the return value.
Your interpreteSport function has a signature of: string -> int -> unit, where unit is the special type that means 'no value', similar to C# void, but with the big difference that unit is an expression that you can correctly assign to a value, while void is just a keyword, and you cannot assign a variable to void in C#.
OK, so, when you call your function passing only the first parameter (a string), what you obtain is an expression of type int -> unit, that is another function that expects and integer and returns unit.
Because this expression is in a branch of a match expression, and because all the branches of a match expression must return the same type, the other 2 branches are also expected to return an int -> unit function, what it's not, and that explain your second error.
More on this in a moment, but before, we must look at the first error reported by the compiler, caused by this line of code:
:? Team as teamSport -> interpretSport(teamSport.Name,teamSport.numberOfPlayers)
Here, you are thinking your are calling your function with 2 parameters, but your are actually not: when you put 2 values in parenthesis, separated by a comma, you are creating a tuple, that is, a single value composed of two or more values. It's like your are passing again only the first parameter, but now with the wrong type: the first parameter of you function is a string, and you are instead passing a tuple: ('a * 'b) is how F# represents tuples: that means a single value composed of a value of type 'a (generic, in your case string) and another of type 'b (generic, in your case integer).
To call your function correctly you must call it so:
:? Team as teamSport -> interpretSport teamSport.Name teamSport.numberOfPlayers
But even if you limit yourself to this correction you will have all the same the second error because, remember, the first expression of your match returns a partially applied funcion, so int -> unit (a function that expects an integer and returns a unit) while your second and your third expressions are now of type unit, because they actually call two functions that return unit (interpreteSport and printfn). To completely fix your code, as has already been said in other answers, you must supply the missing integer parameter to the first call, so:
let matchSport (sport:Sport) =
match sport with
| :? Individual -> interpretSport sport.Name 1
| :? Team as teamSport -> interpretSport teamSport.Name teamSport.numberOfPlayers
| _ -> printfn "not a sport"
If this is a F# learning exercise then it's best to avoid classes and inheritance completely. The fundamental idiomatic F# types are records and discriminated unions.
The intent of your code is not clear to me at all, but I have attempted to refactor to remove the use of classes:
type Players =
| Individual
| Team of numberOfPlayers:int
type Sport = { Name : string; Players : Players }
let MK = { Name = "Combate Mortal"; Players = Individual }
let SF = { Name = "Lutadores de Rua"; Players = Individual }
let Tk = { Name = "Tekken Chupa"; Players = Individual }
let MvC = { Name = "Marvel Contra Capcom"; Players = Team 3 }
let Dbz = { Name = "Bolas do Dragao"; Players = Team 3 }
let interpretSport (sport:Sport) =
let players =
match sport.Players with
| Individual -> ""
| Team numberOfPlayers -> sprintf ". No of players: %d" numberOfPlayers
let rank =
match sport.Name with
| "Combate Mortal" -> Some 1
| "Lutadores de Rua" -> Some 2
| "Tekken Chupa" -> Some 3
| "Bolas do Dragao" -> Some 4
| "Marvel Contra Capcom" -> Some 5
| _ -> None
match rank with
| Some r -> printfn "Rank%d%s" r players
| None -> printfn "not a sport in our list..."
Your function interpretSport has two arguments but your first call to it has only one. Try calling it like so:
| :? Individual -> interpretSport sport.Name 1
Also, the second call uses tupled parameters but the function is declared to take curried parameters. Try calling it like so:
| :? Team as teamSport -> interpretSport teamSport.Name teamSport.numberOfPlayers
There are several small problems with your code. The most obvious is in matchSport, you are calling interpretSport in an uncurried style, with an argument tuple. The call should look like:
Team as teamSport -> interpretSport teamSport.Name teamSport.numberOfPlayers
However, that's a problem, because on the first case of the pattern matching you call interpretSport with only one argument, so you partially apply it and you get a type int -> unit, but when you fully apply it on the second case you get unit, and of course all types of the pattern matching cases must match. The cheapest solution would be to add a 1 to your call on the first case like this:
Individual -> interpretSport sport.Name 1
But you probably want to use the sports you bound before (maybe in a list you give as a parameter) to do the checking. It is in general a bad idea (in functional programming and elsewhere) to hard-code that many strings, you probably want to do some kind of association List, or Map of the Sports to the Ranks, then fold over the sports List and match when found with individual or team and then print whatever the Map gives you for that case. This would be shorter and more extensible.

How to avoid long pattern match based functions?

When using union types with quite a few constructors I almost always find myself implementing lots of logic in single function, i.e. handling all cases in one function. Sometimes I would like to extract logic for single case to separate function, but one cannot have a function accepting only one "constructor" as parameter.
Example:
Assume that we have typical "expression" type :
type Formula =
| Operator of OperatorKind * Formula * Formula
| Number of double
| Function of string * Formula list
[...]
Then, we would like to calculate expression :
let rec calculate efValues formula =
match formula with
| Number n -> [...]
| Operator (kind, lFormula, rFormula) -> [...]
| [...]
Such function would be very long and growing with every new Formula constructor.
How can I avoid that and clean up such code? Are long pattern matching constructs inevitable?
You can define the Operator case of the Formula union using an explicit tuple:
type Formula =
| Operator of (string * Formula * Formula)
| Number of double
If you do this, the compiler will let you pattern match using both Operator(name, left, right) and using a single argument Operator args, so you can write something like:
let evalOp (name, l, r) = 0.0
let eval f =
match f with
| Number n -> 0.0
| Operator args -> evalOp args
I would find this a bit confusing, so it might be better to be more explicit in the type definition and use a named tuple (which is equivalent to the above):
type OperatorInfo = string * Formula * Formula
and Formula =
| Operator of OperatorInfo
| Number of double
Or perhaps be even more explicit and use a record:
type OperatorInfo =
{ Name : string
Left : Formula
Right : Formula }
and Formula =
| Operator of OperatorInfo
| Number of double
Then you can pattern match using one of the following:
| Operator args -> (...)
| Operator { Name = n; Left = l; Right = r } -> (...)
I would say you typically want to handle all the cases in a single function. That's the main selling point of unions - they force you to handle all the cases in one way or another. That said, I can see where you're coming from.
If I had a big union and only cared about a single case, I would handle it like this, wrapping the result in an option:
let doSomethingForOneCase (form: Formula) =
match form with
| Formula (op, l, r) ->
let result = (...)
Some result
| _ -> None
And then handle None in whatever way is appropriate at the call site.
Note that this is in line with the signature required by partial active patterns, so if you decide that you need to use this function as a case in another match expression, you can easily wrap it up in an active pattern to get the nice syntax.

Appropriate use of active patterns in F#

I'm using an active pattern to parse usage events in a csv formatted usage log. The active pattern part is listed below. Parsing the whole file in works well and the sequence that is produced is filled with all sorts of UsageEvents.
type SystemName = string
type SystemVersion = string
type MAC = string
type Category = string
type Game = string
type Setting = string
type StartupLocation = string
type UsageEvent =
| SystemStart of DateTime * SystemVersion * SystemName * MAC
| SystemEnd of DateTime
| GameStart of DateTime * Category * Game * Setting * StartupLocation
| GameEnd of DateTime * Category * Game
| Other
let (|SystemStart|SystemEnd|GameStart|GameEnd|Other|) (input : string list) =
match List.nth input 0 with
| "SystemStartedEvent" ->
SystemStart (DateTime.Parse (List.nth input 1), List.nth input 2, List.nth input 3, List.nth input 4)
| "SystemEndedEvent" ->
SystemEnd (DateTime.Parse (List.nth input 1))
| "GameStartedEvent" ->
GameStart (DateTime.Parse (List.nth input 1), List.nth input 2, List.nth input 3, List.nth input 4, List.nth input 5)
| "GameEndedEvent" ->
GameEnd (DateTime.Parse (List.nth input 1), List.nth input 2, List.nth input 3)
| _ ->
Other
The problem I have is that I'm probably using the ActivePattern in the wrong way. I'd like to walk the list to create a tree out of it based on some logic, but I have no way to match an entry in the sequence after parsing.
let CountSystemStart (entries : UsageEvent list) =
let rec loop sum = function
| SystemStart(_,_,_,_) -> sum + 1
| _ -> sum
loop 0 entries
This matching does not work because the loop function required a string list. In what other way could I use the data contained in the unions or should I match the input and then store it in a regular type?
To add to #Petr's answer - UsageEvent cases and your active pattern cases have the same names, so the active pattern which is defined later shadows the union type. That's where the string list thing comes from, most likely.
I would just drop the active pattern altogether, and add a Parse function (or rather a ParseParts, since you want to feed it a list of strings) to the UsageEvent.
type UsageEvent =
| SystemStart of DateTime * SystemVersion * SystemName * MAC
| (...and so on...)
static member ParseParts (input: string list) =
match input with
| ["SystemStartedEvent"; date; version; name; mac] ->
SystemStart (DateTime.Parse date, version, name, mac)
| (...and so on...)
Active patterns are cute, but you really need a good scenario for them to shine. Otherwise if you can get away with using a plain function, just use a plain function.
There are 2 problems with this code:
Discriminated union UsageEvent and active pattern choice functions have the same names
recursive loop function is not recursive as it is written - it doesn't call itself.
When you are matching on UsageEvent list try use full type name.
I would rewrite your CountSystemStart function as:
let CountSystemStart (entries : UsageEvent list) =
let rec loop sum = function
| [] -> sum
| (UsageEvent.SystemStart(_))::rest -> loop (sum + 1) rest
| _::rest -> loop sum rest
loop 0 entries

Randomly choose an instance from union in F#

In F#, given
type MyType = A | B | C | D | E | F | G
How do I randomly define an instance of MyType?
This ought to work:
let randInst<'t>() =
let cases = Reflection.FSharpType.GetUnionCases(typeof<'t>)
let index = System.Random().Next(cases.Length)
let case = cases.[index]
Reflection.FSharpValue.MakeUnion(case, [||]) :?> 't
This code assumes that the union cases are all nullary and that the type you're using is actually a union type, but it would be easy to explicitly check those assumptions and throw meaningful exceptions if desired.
Select a random number, then pattern match that number with different branches returning a different instant?

Resources