Reputation: 13109
I'm starting with F# and I read about recursive Union Types on https://fsharpforfunandprofit.com/posts/fsharp-in-60-seconds//
Given the example from the link
type Employee =
| Worker of Person
| Manager of Employee list
How can I create a value of type Manager
and assign a List of Workers to it?
I can create a value of type Worker
like this:
let john = {First = "John"; Last="Doe"}
let worker = Worker john
But I don't know how to create a value jane
of type Manager
having john
assigned as an item of the Empoyee
list:
let jane = { First="Jane"; Last="Doe" }
let manager = Manager [worker]
This works, but I can't assign First
and Last
from jane
to manager
.
Is manager meant to have no First
/ Last
at all in this example?
How would I have to change the type definition for Manager to have both a list of Employee
?
In addition it also looks like Manager
doesn't have a member employees
I can access after creating a value of type Manager
?
Upvotes: 3
Views: 100
Reputation: 80805
Given that type definition, a manager cannot have first/last name. The type definition does not include anything like that.
To make Manager
work similarly to Worker
in this regard, just give it a Person
value:
type Employee = Worker of Person | Manager of Person * Employee list
Then you can create a manager Jane:
let manager = Manager ({ First = "Jane"; Last = "Doe" }, [worker])
As for a member employees
, there are several things to say.
First, stay away from members. F# is functional-first. Functions are better than members (for reasons that I'm not going to go into here). Have a function:
let employees emp =
match emp with
| Manager (_, emps) -> emps
| Worker _ -> ??? // what to return if the employee turned out to be worker?
And right away you can see a difficulty: when the employee is a Manager
, sure, we can return their employees. But what if it's a Worker
? What to return then?
One reasonable suggestion would be to return an empty list, because, after all, a Worker
doesn't have any employees working for them, right?
let employees emp =
match emp with
| Manager (_, emps) -> emps
| Worker _ -> []
Another possibility would be to return an Option
. Which approach is "correct" depends on what you're going to do with the result, so only you can answer that.
But if you absolutely insist on having a member (and please, please carefully think about why you need it), you can definitely add a member to your type like this:
type Employee = Worker of Person | Manager of Person * Employee list
with
member this.employees =
match this with
| Manager (_, emps) -> emps
| Worker _ -> []
Upvotes: 3