A friend and I are reading up on F# and are messing around with records at the moment.
We have made the following record for representing a person:
type Person =
{name: string;
father: Person;
mother: Person;}
F# Interactive accepts it, and in some way, the type makes sense, except we can't see how to use it. When we try to declare a person, we have to declare the parents at the point of declaration, and in turn declare their parents and so on. Is there any way to actually use this type? And if not, how come we are even able create it?
PS: We are well aware that since parents are intended to be optional, we should have encapsulated them with the option (Some x | None) type.
EDIT
My question is not how to fix the above, a solution is already written in the PS.
My question is, can I actually use the above type, e.g. declare a Person record of the above form? If not, I must have made an unusable type. Why can I make such a type?
Lee shows a more useful definition, but you can create an instance of your Person type:
let rec loopy = { name = "loopy"; father = loopy; mother = loopy }
or
let rec male = { name = "male"; father = male; mother = female }
and female = { name = "female"; father = male; mother = female}
Of course, these aren't at all helpful if you're modeling real people, but the compiler doesn't know that. A similar recursive type could be useful if you're trying to define a cycle, for instance.
If you declare father and mother as Parent option then you can use it like:
let f = { name = "Father"; father = None; mother = None }
let m = { name = "Mother"; father = None; mother = None }
let c = { name = "Child"; father = Some(f); mother = Some(m) }
without using Parent option for father and mother you would have to create a "null parent" instance and use that instead of None.
Related
Assume u have the following recursive record type
type Parent = {
Name : string
Age : int
Children : Child list }
and Child = {
Name : string
Parent : Parent option }
I can easily create instances with
module Builder =
let create name kids =
let rec makeChild kid = { kid with Parent = parent |> Some }
and parent =
{
Name = name
Age = 42
Children = children
}
and children = kids |> List.map makeChild
parent
let createChild name =
{ Child.Name = name; Parent = None }
But when i try to "transform" an existing adult into a parent using "with" like that:
module Builder2 =
let createAdult name age =
{ Parent.Name = name; Age = age; Children = [] }
let create name kids =
let rec makeChild kid = { kid with Parent = parent |> Some }
and parent =
{ (createAdult name 42) with
Children = children
}
and children = kids |> List.map makeChild
parent
let createChild name =
{ Child.Name = name; Parent = None }
I get:
error FS0040: This and other recursive references to the object(s) being defined will be checked for initialization-soundness at runtime through the use of a delayed reference. This is because you are defining one or more recursive objects, rather than recursive functions. This warning may be suppressed by using '#nowarn "40"' or '--nowarn:40'.
and "Children = children" in the "parent" definition is highlighted.
What am i doing wrong?
Edit:
One more point: when i move the "Builder" (which worked) into a different assembly (e.g. the test assembly) it immediately stops working with:
error FS0261: Recursive values cannot be directly assigned to the non-mutable field 'Children' of the type 'Parent' within a recursive binding. Consider using a mutable field instead.
Edit:
Based on the comments I tried
let create name kids =
let rec makeChild kid = { kid with Parent = parent |> Some }
and adult = createAdult name 42
and parent =
{ adult with Children = children }
and children = kids |> List.map makeChild
but still no luck - the compiler still does not see this usecase similar to the working one :(
First of all, the message you posted in your question is just a warning - it tells you that you can only initialize a recursive value if the construction does not evaluate the entire value immediately (this cannot be done when the first value depends on the second and vice versa).
You can sometimes just ignore the warning, but in your case, the values are actually mutually dependent, so the following gives an error:
Builder2.create "A" [Builder2.createChild "B"]
System.InvalidOperationException: ValueFactory attempted to access the Value property of this instance.
One way to introduce some form of delay is to change the parent to include children as a lazy sequence seq<'T> rather than a fully evaluated list list<'T>:
type Parent = {
Name : string
Age : int
Children : Child seq }
and Child = {
Name : string
Parent : Parent option }
Then you also need to change Builder2 to use Seq.map (to keep things lazy):
let create name kids =
let rec makeChild kid = { kid with Parent = parent |> Some }
and parent =
{ (createAdult name 42) with
Children = children
}
and children = kids |> Seq.map makeChild
Now you still get the warning (which you can turn off), but the following works and creates a recursive value:
let p = Builder2.create "A" [Builder2.createChild "B"]
As an aside, I think it is probably better to avoid recursive values - I suspect that one way reference (parent referencing children, but not the other way round) would let you do what you need - and your code would likely be simpler.
cartermp found and posted the solution here:
https://github.com/Microsoft/visualfsharp/issues/4201
I published a repro here
https://github.com/plainionist/DevNull/tree/master/src/FSharpCopyRecordRecursive
and of course the proposed solution works like a charm
Suppose we had a table of vendors in a SQL database that we want to load into F#:
+----+--------+--------+
| ID | Name | Parent |
+----+--------+--------+
| 1 | Nest | 2 |
| 2 | Google | NULL |
| 3 | Apple | NULL |
+----+--------+--------+
Using type providers it is easy enough to get the table into F#, but suppose we wanted to then convert the data into a sequence of Vendors, where Vendor is a type like this:
Vendor = {ID: int; Name: String; Parent: Vendor option}
How would one go about doing that? The issue is that when creating the sequence of Vendors we can't map to each row a particular Vendor, since we don't have the sequence of Vendors yet. It would be good to also assume that the application allows for cycles (A could have B as a parent and B could have A as a parent), although in the case of vendors that doesn't really make sense.
You could instead define the Vendor type as:
Vendor = {ID: int; Name: String; ParentID: int option}
But this seems much less elegant, since every time you would want to reference the parent vendor you'd have to do some sort of lookup. Is there a known solution to this? It seems like a situation that could occur often (especially when dealing with graphs or trees).
It also seems like a solution could involve some sort of lazy evaluation, but it's not clear to me how the Lazy<'T> type in F# could be applied here.
It's not a particularly elegant solution, but the one that uses lazy evaluation for the parent would look something like this: you would have two types, one that matches the schema of your table and one recursive:
type Flat = { ID: int; Name: string; ParentID : int option}
type Recursive = { ID: int; Name: string; Parent: Lazy<Recursive> option}
Then let's set up something that looks like your table:
let records =
[
{ ID = 1; Name = "Nest"; ParentID = Some 2 }
{ ID = 2; Name = "Google"; ParentID = None }
{ ID = 3; Name = "Apple"; ParentID = None }
{ ID = 4; Name = "Yin"; ParentID = Some 5 }
{ ID = 5; Name = "Yang"; ParentID = Some 4 }
]
|> List.map (fun x -> x.ID, x)
|> Map.ofList
let getRecord recID = records |> Map.find recID
And you can put it together like this:
let rec getRecordRecursive recID =
let record = getRecord recID
{
ID = record.ID
Name = record.Name
Parent =
record.ParentID
|> Option.map (fun pid ->
Lazy.Create <| fun () ->
getRecordRecursive pid)
}
So in a sense you're using the lazy type to delay the next step of recursion until you need it. Otherwise getRecordRecursive 4 would give you a stack overflow.
But there are tradeoffs - you no longer get nice behaved equality on such records, for instance. I'm not convinced you're not better off with Flat records in the long run.
I need to serialize arbitrary records into maps/dictionary.
I imagine my end type look like this:
type TabularData= array<Map<string, obj>>
But I have problems in build a generic function that accept any record and turn them into Map.
In practice, the best advice is probably to use some existing serialization library like FsPickler. However, if you really want to write your own serialization for records, then GetRecordFields (as mentioned in the comments) is the way to go.
The following takes a record and creates a map from string field names to obj values of the fields. Note that it does not handle nested records and it is not particularly fast:
open Microsoft.FSharp.Reflection
let asMap (recd:'T) =
[ for p in FSharpType.GetRecordFields(typeof<'T>) ->
p.Name, p.GetValue(recd) ]
|> Map.ofSeq
Here is a little example that calls this with a simple record:
type Person =
{ Name : string
Age : int }
asMap { Name = "Tomas"; Age = -1 }
Using the same idea mentioned by Tomas, you can create a IDictionary<K,V> from a record like this:
let asDictionary (entity: 'T) =
seq {
for prop in FSharpType.GetRecordFields(typeof<'T>) ->
prop.Name, prop.GetValue(entity)
} |> dict
If I want to change a value on a list, I will return a new list with the new value instead of changing the value on the old list.
Now I have four types. I need to update the value location in varEnd, instead of changing the value, I need to return a new type with the update value
type varEnd = {
v: ctype;
k: varkind;
l: location;
}
;;
type varStart = {
ct: ctype;
sy: sTable;
n: int;
stm: stmt list;
e: expr
}
and sEntry = Var of varEnd | Fun of varStart
and sTable = (string * sEntry) list
type environment = sTable list;;
(a function where environment is the only parameter i can use)
let allocateMem (env:environment) : environment =
I tried to use List.iter, but it changes the value directly, which type is also not mutable. I think List.fold will be a better option.
The biggest issue i have is there are four different types.
I think you're saying that you know how to change an element of a list by constructing a new list.
Now you want to do this to an environment, and an environment is a list of quite complicated things. But this doesn't make any difference, the way to change the list is the same. The only difference is that the replacement value will be a complicated thing.
I don't know what you mean when you say you have four types. I see a lot more than four types listed here. But on the other hand, an environment seems to contain things of basically two different types.
Maybe (but possibly not) you're saying you don't know a good way to change just one of the four fields of a record while leaving the others the same. This is something for which there's a good answer. Assume that x is something of type varEnd. Then you can say:
{ x with l = loc }
If, in fact, you don't know how to modify an element of a list by creating a new list, then that's the thing to figure out first. You can do it with a fold, but in fact you can also do it with List.map, which is a little simpler. You can't do it with List.iter.
Update
Assume we have a record type like this:
type r = { a: int; b: float; }
Here's a function that takes r list list and adds 1.0 to the b fields of those records whose a fields are 0.
let incr_ll rll =
let f r = if r.a = 0 then { r with b = r.b +. 1.0 } else r in
List.map (List.map f) rll
The type of this function is r list list -> r list list.
I am currently working with a three-level process for which I need some information to flow being accessed and updated. The information is also three-leveled, in such a way that a process at one level may need to access/update information at its level and at higher levels.
type info_0 = { ... fields ... }
type info_1 = { ... fields ... }
type info_2 = { ... fields ... }
fun0 will do some stuff with an info_0, then pass it to fun1 along with an info_1, then get back the resulting info_0 and proceed, calling another fun1 with another info_1.
The same happens at the lower level.
My current representation has
type info_0 = { ... fields ... }
type info_1 = { i0: info_0; ... fields ... }
type info_2 = { i1: info_1; ... fields ... }
In fun2, updating info_0 get pretty messy:
let fun2 (i2: info_2): info_2 =
{
i2 with
i1 = {
i2.i1 with
i0 = update_field0 i2.i1.i0
}
}
Something simpler would be:
type info_0 = { ... fields ... }
type info_1 = { ... fields ... }
type info_2 = { ... fields ... }
type info_01 = info_0 * info_1
type info_012 = info_0 * info_1 * info_2
let fun2 (i0, i1, i2): info_012 =
(update_field0 i0, i1, i2)
Does the last solution look good?
Is there an even better solution to this kind of problem? (for instance, one where I could write a function that can handle updating a field0, no matter whether it's dealing with a info_0, info_1 or info_2)
Would OCaml modules help? (I could include a Sig0 inside Sig1 for instance...)
What you need is an idiomatic way of updating nested immutable data structures. I don't know any relevant work in OCaml, but there are a few techniques available in Scala/Haskell including Zippers, Tree rewriting, and Functional lenses:
Cleaner way to update nested structures
Is there a Haskell idiom for updating a nested data structure?
For F#, a descendant of OCaml, functional lenses gives a nice solution. Therefore, lenses is the most relevant approach here. You can get the idea of using it from this thread:
Updating nested immutable data structures
since F# record syntax is almost the same as that of OCaml.
EDIT:
As #Thomas mentioned in his comment, there is a complete implementation of lenses in OCaml available here. And particularly, gapiLens.mli is of our interest.
You seem to want the ability to treat a more complex value as though it was a simpler one. This is (more or less) the essence of the OO model. I usually try to avoid the OO subset of OCaml unless I really need it, but it does seem to meet your needs here. You would have a base class corresponding to info_0. The class info_1 would be a subclass of info_0, and info_2 would be a subclass of info_1. It's worth thinking about, anyway.
As Jeffrey Scofield suggested, You can save the hassle at use and update time by using classes: make info_1 a derived class, and a subtype, of info_0, and so on.
class info_1 = object
inherit info_0
val a_1_1 : int
…
method update_a_1_1 v = {<a_1_1 = v>}
end
…
let x : info_1 = new info_1 … in
let y = x#update_a_1_1 42 in
…
The downside of this direct object approach is that all the data in an object is copied if you update any of the fields; you can't share the info_0 pieces between x and y.
You can use objects and retain the sharing behavior from your design with records, but the boilerplate at definition time and the constant run-time overhead become larger.
class info_1 = object
val zero : info_0
method get_a_0_1 = zero#get_a_0_1
method update_a_0_1 = {<zero = zero#update_a_0_1>}
val a_1_1 : int
method get_a_1_1 = a_1_1
method update_a_1_1 v = {<a_1_1 = v>}
end
let x : info_1 = new info_1 … in
let y = x#update_a_1_1 42 in
…