I am trying to create a record which uses one of the previously defined fields to calculate the value of another, within the same constructor. e.g.
myRecordType = {Foo:int; Bar:int[]}
myRecord = {Foo = 5;
Bar = Array.init Foo (fun i -> i)}
When I try this it doesn't recognise Foo as already existing. I also can't reference Foo using myRecord.Foo, but that makes sense since myRecord hasn't been constructed yet. However I would've thought that Foo and Bar would be in the same scope, so Bar could access Foo, but apparently not.
The size of the Bar array depends on the value of Foo, so how is it possible to set up a record of this format?
You cannot reference other fields, you shouldn't even take for granted the order of fields evaluation.
You can do it by additional let binding:
let myrecord =
let calcedFoo = 5
{ Foo = calcedFoo; Bar = Array.init calcedFoo id }
You can think of record construction expression as a function where right sides of assignments are parameters passed to that function.
I would go with what #Bartek suggests and use local let binding to store all pre-computed values that you need to have before you can create the record.
That said (depending on your domain), you might also be able to change the structure of your record, so that you have one record with all the primary values and another record that contains the primary one and adds all secondary values:
type MyRecordPrimary = { Foo:int }
type MyRecord = { Primary:MyRecordPrimary; Bar:int[] }
let myPrim = { Foo = 5 }
let myRec = { Primary = myPrim; Bar = Array.init myPrim.Foo (fun i -> i)}
Doing this just to make the construction a bit shorter would be silly, but if the primary record actually represents something in your domain, then this might be a good alternative.
Related
I have a common pattern:
type something =
{
... a lot of stuff
}
member this.Description =
"a string description of the content, can be long tables, etc"
I would like the Description property to be evaluated ONLY when I need it; in many cases, it won't be used, but it could (mostly on a user's request).
I noticed that this code will cause Description to be evaluated even when it is not needed. So I moved the code to a function: Describe () and it solves the problem.
As I'm refactoring, I'm revisiting this. And while it won't make anything better in practice, I was wondering if something like:
member this.Describe =
(lazy "the long to build text output").Value
would solve the problem? because the lazy object will be created, but nothing may query the value itself.
Would that work reliably?
The way you're declaring the property, it's essentially a function. It doesn't have any parameters, but the code in its body is executed every time somebody tries to read its value. This is how properties work in .NET in general.
This means that whatever you put inside of it, would still execute on every access. Try this:
type T() =
member this.Y =
printfn "Accessing value of Y"
42
let t = T()
let a = t.Y
let b = t.Y
let c = t.Y
You should see "Accessing value of Y" printed out three times.
And it doesn't matter if you wrap the whole thing in lazy: you're still constructing a brand new Lazy object on every access to the property, then immediately reading its value, thus causing its body to evaluate.
If you really want to (1) defer evaluation until required and/or (2) cache evaluated value, you should create the Lazy object outside of the property's body, and then have the property read its value, so that it's the same Lazy object being read on every property access:
type T() =
let x = lazy (
printfn "Calculating value of X"
"expensive computation"
)
member this.X = x.Value
let t = T()
let a = t.X
let b = t.X
let c = t.X
This will print "Calculating value of X" only once.
Please, help an F# beginner understand this! I have the following F# code (which I've just created to help me learn, so I realise it's probably terrible):
type Account = {
ID: Guid
Name: string
};
module Accounts =
let mutable accounts:Account list = []
// Why does this always return empty?
let lst =
accounts
let load id =
accounts |> List.find(fun a-> a.ID = id)
let save account =
accounts <- account::accounts
Accounts.save { ID = Guid.NewGuid(); Name = "Account One"}
let id = Guid.NewGuid()
Accounts.save { ID = id; Name = "Account Two"}
let account = Accounts.load id
If I write out the value of account at this stage (after the above code), I see the Account record I expect (Account Two), and if I dump Accounts.accounts, I can see that the mutable list contains both Account records.
So why does Account.lst always return an empty list, even though I can see that the list definitely isn't empty?
Because lst is a value, not a function.
In F#, the technical difference between a value and a function is that a function has parameters, and a value does not.
When you declared lst, you didn't give it any parameters, so the compiler understood it as "I want to take the value of accounts at this particular point in time, and refer to that value as lst from now on". So every time you write lst, you're not calling a function, but merely referring to that same empty list that was the value of accounts at initialization time.
To make lst a true function, you need to give it a parameter. And because it doesn't really need any actual data, the natural parameter to give it is the unit value - ().
let lst () = accounts
P.S. This whole trickiness ultimately comes from mutating state. Try to avoid it when possible.
Because lst is a value not a function. You need to convert it to a function:
let lst () =
accounts
then you can call it by:
Accounts.lst()
This question is in follow up to an earlier question, Preserving Field names across the F#/C# boundary
Because of the current limitation encountered with F# type providers (see the earlier question), I want to map the type-provider-generated list to my own list of records, in which the record is, in part,
type inspection = {
inspectionID : string;
inspectorID : int;
EstablishmentID : string;
EstablishmentName : string; // other members elided
}
I think the way to do this will use Seq.map, but I am not certain. (Recall I am doing a learning exercise.) So here is what I tried:
type restaurantCsv = CsvProvider<"C:\somepath\RestaurantRatings2013.csv",HasHeaders=true>
// which generates a type, but it is an "erased" type, so member names do not propogate
// over to C#.
type RawInspectionData(filename : string) =
member this.allData = restaurantCsv.Load(filename) // works fine
member this.allInspections =
this.allData.Data
|> Seq.map(fun rcrd -> new inspection[{inspectionID = rcrd.InspectionID;}])
and, of course, the complete statement would have the other member names as part of the inspection, here elided for brevity. Someone pointed me to p 43 of F# For Scientists, which is why I thought to use this format with the curly braces. But this yields a syntax error, "Unexpected symbol '{' in expression. Expected ',', ']' or other token."
Hopefully, though, this snippet is adequate to show what I would like to do, create a Generated Type from the Erased Type. How can I accomplish this?
Your code is going in the right direction. When using Seq.map (which is like Select in LINQ), you need to turn a single element of the original sequence into a single element of the new sequence. So the lambda function just needs to create a single instance of the record.
A record is constructed using { Field1 = value1; Field2 = value2; ... } so you need:
type RawInspectionData(filename : string) =
let allData = restaurantCsv.Load(filename) // works fine
member this.allInspections =
allData.Data
|> Seq.map(fun rcrd -> {inspectionID = rcrd.InspectionID})
I also changed allData from a member to a local let definition (which makes it private field of the class). I suppose that your original code new inspection[{...}] tried to create a singleton array with the element - to create an array you'd write [| { Field = value; ... } |] (and the compiler would infer the type of the array for you). But in this case, no arrays are needed.
so i have got a type Genre with Property Name on it.
Im creating a list of Genre Names like below.
let genres = new Genre()
[ genres.Name <- "Disco";
genres.Name <- "Jazz";
genres.Name <- "Rock"; ] |>ignore
Wondering if there is more succint way of creating this ?.
The code in your example creates just a single Genre object and then creates a list of unit values. A unit value is a bit like void in C# - it is the result of perfroming an expression that does not return anything, but has a side-effect. In your case, the side-effect is modifying the Name property of the single instance (that's what the <- operator does), so you end with a single genres value whose Name is "Rock".
There are numerous ways to change the code to do what you want - to start with what you wrote:
let genre = new Genre()
genre.Name <- "Disco"
This creates a single genre value, so you could create values genre1, genre2 and genre3 and then turn them into a list using:
let genres = [ genre1; genre2; genre3 ]
That would be quite a lot of repetition. If you have a default constructor for Genre that takes the name, you can just write Genre("Disco"). If you don't, you can use F# object initialization syntax and specify the value of the property during the construction as Genre(Name="Disco"). Note you can also omit new if the object does not implement IDisposable.
Now you can construct a list like this:
let genres = [ Genre(Name="Disco"); Genre(Name="Jazz"); Genre(Name="Rock") ]
Now, you can start using functional features like List.map (as suggested by Daniel) or F# list comprehension syntax to make the construction even shorter. In this case, I would probably prefer list comprehension and I'd write:
let genres = [ for name in ["Disco"; "Jazz"; "Rock"] -> Genre(Name = name) ]
This does the same thing as List.map, but using an F# syntax that has been designed for this purpose.
EDIT: Aside, using mutable properties in F# is not always the best way to go. You could try solving the same problem using F# records, which give you an easy way to create copies with modified properties. For example:
// A genre has a name and an era
type Genre = { Name : string; Era : string; }
// Create a template with the basic properties set
let template = { Name = "Default"; Era = "Twentieth century" }
// Create a list of 20th century genres
let genres = [ { template with Name = "Disco" }
{ template with Name = "Jazz" }
{ template with Name = "Rock" } ]
Unlike in the previous case, records are immutable and so you don't risk the confusion that is caused when you create a mutable object and then mutate it. Here, you get a list of three different objects (that are created by copying the template).
["Disco"; "Jazz"; "Rock"]
|> List.map (fun name -> Genre(name))
I think the simplest way would be to use a construcotr which did the assignment for you, then you could write
let genres = Genre("Disco")::Genre("Jazz")::Genre("Rock")::[]
Slightly more terser:
type Genre = Genre of string
let genres = List.map Genre ["Disco"; "Jazz"; "Rock"]
printfn "%A" genres
Prints [Genre "Disco"; Genre "Jazz"; Genre "Rock"].
I have a factory class that creates objects with circular references. I'd like them to be immutable (in some sense of the word) too. So I use the following technique, using a closure of sorts:
[<AbstractClass>]
type Parent() =
abstract Children : seq<Child>
and Child(parent) =
member __.Parent = parent
module Factory =
let makeParent() =
let children = ResizeArray()
let parent =
{ new Parent() with
member __.Children = Seq.readonly children }
[Child(parent); Child(parent); Child(parent)] |> children.AddRange
parent
I like this better than an internal AddChild method because there's a stronger guarantee of immutability. Perhaps it's neurotic, but I prefer closures for access control.
Are there any pitfalls to this design? Are there better, perhaps less cumbersome, ways to do this?
You can use F#'s support for recursive initialization even when creating an instance of abstract class:
let makeParent() =
let rec children = seq [ Child(parent); Child(parent); Child(parent) ]
and parent =
{ new Parent() with
member __.Children = children }
parent
When compiling the code, F# uses lazy values, so the value children becomes a lazy value and the property Children accesses the value of this lazy computation. This is fine, because it can first create instance of Parent (referencing the lazy value) and then actually construct the sequence.
Doing the same thing with records wouldn't work as nicely, because none of the computations would be delayed, but it works quite nicely here, because the sequence is not actually accessed when creating the Parent (if it was a record, this would be a field that would have to be evaluated).
The F# compiler cannot tell (in general) whether this is correct, so it emits a warning that can be disabled using #nowarn "40".
In general, I think that using let rec .. and .. to initialize recursive values is a good thing - it is a bit limited (one of the references must be delayed), but it forces you to keep the recursive references isolated and, I think, it keeps your code simpler.
EDIT To add an example when this may go wrong - if the constructor of Child tries to access the Children collection of its parent, then it forces evaluation of the lazy value before it can be created and you get a runtime error (which is what the warning says). Try adding this to the constructor of Child:
do printfn "%d" (Seq.length parent.Children)
I think that Tomas's answer is the way to go. However, for completeness I'll show how you could use recursive records to create cyclic immutable objects. This can potentially get quite ugly, so I've hidden the immutable record implementation behind some nicer properties:
type Parent = internal { children : Children option }
and internal Children = { first : Child; rest : Children option }
and Child = internal { parent : Parent }
let rec internal listToChildren = function
| [] -> None
| c::cs -> Some { first = c; rest = listToChildren cs }
let rec internal childrenToList = function
| None -> []
| Some { first = c; rest = cs } -> c::(childrenToList cs)
module Factory =
let makeParent() =
let rec parent = { children = children }
and child1 = { parent = parent }
and child2 = { parent = parent }
and child3 = { parent = parent }
and children = [child1; child2; child3] |> listToChildren
parent
type Parent with
member p.Children = childrenToList p.children
type Child with
member c.Parent = c.parent
I guess something like this can also be done:
type ParentFactory private (n) as X =
inherit Parent()
let childs = [for i=1 to n do yield Child(X :> Parent)]
override X.Children = childs |> List.toSeq;
static member Create n = (new ParentFactory(n)) :> Parent