Any simpler way to make a lazy property? - f#

I would like to load data only when needed.
At start I used auto property.
type DataFromCsv(path) =
...
member val A1 = MyCsvType.Load(path1)
member val A2 = MyCsvType.Load(path2)
member val A3 = MyCsvType.Load(path3)
member val A4 = MyCsvType.Load(path4)
It is sort of lazy till I instantiate the object let my_data = DataFromCsv(path), at which time all the files are loaded, which is not ideal.
My another attempt is to use lazy for each property.
type DataFromCsv(path) =
let a1 = lazy (MyCsvType.Load(path1))
let a2 = lazy (MyCsvType.Load(path2))
member this.A1 = a1.Force()
member this.A2 = a2.Force()
It works, but I feel it is a bit cumbersome. Furthermore, a1 is only used by member this.A1 but it is visible anywhere in the object.
So, is there a kind of auto lazy property, so that I can do such things more elegantly?

Related

Will the use of lazy in an F# property prevent the code from being evaluated when it shouldn't?

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.

How to memoize the result of a property of a Discriminated Union in F#

I have a Discriminated Union ("DU") type and a property OR method which computes something based on the DU instance. I am trying to achieve a pattern where the instance property performs the calculation the first time it is requested and then remembers the result - akin to a Singleton Pattern in Object Oriented Terms.
I am finding this challenging without the aid of a local instance variable to store the state of things...
I have tried simple memoization of a method but I then run into the problem of not having anywhere (in the instance) to store the memoized result.
Note: there will be many instances of this DU type in my application.
Code
// Terrible mutable variable needed alongside the DU to achieve a singleton-like pattern
let mutable result: int option = None
type DU =
| Good of int
| Bad of int
with
// behaves like a Singleton
member this.GetSomething =
match result with
| None ->
printfn "Big bad side-effect to let us know it's a first time"
// big bad calculation that we only want to do once
let x = 1 + 1
// "memoize" it
result <- Some x
x
| Some y -> y
let instance = Good 1
let f1 = instance.GetSomething // first time
let f2 = instance.GetSomething // second call - no side effect1
You can't memoize inside of an immutable value, because memoization involves changing and maintaining state.
Obviously, you can do it outside of an immutable value:
let smth = getSomething "foo"
As long as you reuse smth instead of calling getSomething "foo" again, you've essentially memoized the result. This is safe if getSomething is referentially transparent; otherwise, it's not.
From the sample code posted in the OP, it looks more like you're looking for lazy initialization, which you can get from the Lazy<T> class. You'll still need an object in which to store the Lazy<T> instance, though.
open System
type MyObject() =
let result =
lazy
printfn "Big bad side-effect to let us know it's a first time"
// big bad calculation that we only want to do once
1 + 1
member this.GetSomething = result.Value
As you can see, in F# you can also use lazy expressions for this.
> let mo = MyObject ();;
val mo : MyObject
> let smth1 = mo.GetSomething;;
Big bad side-effect to let us know it's a first time
val smth1 : int = 2
> let smth2 = mo.GetSomething;;
val smth2 : int = 2
The MyObject class may look immutable, but that's only because state is being kept inside of the lazy expression.
This way it is possible to have a lazy inside a DU.
Because the type is Lazy.
type DU =
| Good of Lazy<int> // Lazy not lazy
| Bad of Lazy<int>
type MyObject() =
let result =
lazy(
printfn "Big bad side-effect to let us know it's a first time"
// big bad calculation that we only want to do once
1 + 1) |> Good
member this.GetSomething = result
let mo = MyObject()
let f() =
match mo.GetSomething with
| Good x -> x.Value
| Bad y -> y.Value
f()
f()
Output
Big bad side-effect to let us know it's a first time
val it : int = 2
>
val it : int = 2

Setting a property of a class when the containing class is constructed

A class Test which upon construction creates an instance of another class and sets a property would look something like this (I suppose):
type Test() as this =
let a = new A()
do this.Init()
member this.Init() =
let a.Size = 10
However, I get a Block following this 'let' is unfinished. Expect an expression.
What is the correct and preferred way of doing this?
If you want to mutate the Size property, you'll have to use the assignment operator:
type Test() as this =
let a = new A()
do this.Init()
member this.Init() =
a.Size <- 10
However, you can write it much more succinctly like this:
type Test() =
let a = A (Size = 10)

looping through F# record like Javascript object

In javascript, I can access every property of an object with a simple for loop as follows
var myObj = {x:1, y:2};
var i, sum=0;
for(i in myObj) sum = sum + myObj[i];
I am wondering if I can do similar thing with F#.
type MyObj = {x:int; y:int}
let myObj = {x=1; y=2}
let allValues:seq<int> = allPropertyValuesIn myObj //How do I implement allPropertyValuesIn
let sum = allValues |> Seq.fold (+) 0
Thank you for your input
Edit to clarify why I want to do such thing
I am working on an XML file generator. The input is rows read from Database, and the xsd is predefined.
Lets say I have a "Product" Element needs to be generated and depending on the business rule, there could be 200 Children element under product some are required, some are optional. Following the advise from this excellent blog, I have had my first (very rough) design for product record:
1. type Product{ Price:Money; Name:Name; FactoryLocation:Address option ... }
2. let product = {Price = Money(1.5); Name = Name ("Joe Tooth Paste"); ... }
3. let child1 = createEl ("Price", product.Price)
..
203. let allChildren = child1
::child2
::child3
..
::[]
404. let prodctEl = createElWithCildren ("Product", allChildren)
This is very tedious and un-succinct. There HAS to be a better way to do such thing in F#. I am not very kin on the reflection idea either.
Are there any other approaches or I am just doing it wrong?
Try this:
open Microsoft.FSharp.Reflection
type MyObj = {x:int; y:int}
let myObj = {x=1; y=2}
let allValues = FSharpType.GetRecordFields (myObj.GetType())
let sum =
allValues
|> Seq.fold
(fun s t -> s + int(t.GetValue(myObj).ToString()))
0
printfn "%d" sum
However, as John Palmer admonishes, there are not very many good reasons for doing something like this.

Is it possible for an object to access private field / function of another object of same class?

I know this is possible in C#, which produces simple and efficient code. --- Two objects of the same class can access each other's private parts.
class c1
{
private int A;
public void test(c1 c)
{
c.A = 5;
}
}
But It seems impossible in F#, is it true?
type c1()
let A = 0
member test (c: c1) = c.A
Interesting question. It seems to work with an explicit field but not with a let binding:
// Works
type c1 =
val private A : int
new(a) = { A = a }
member m.test(c : c1) = c.A
let someC1 = new c1(1)
let someMoreC1 = new c1(42);
let theAnswer = someC1.test someMoreC1
// Doesn't work
type c2() =
let mutable A = 42
// Compiler error: The field, constructor or member 'A' is not defined
member m.test(c : c2) = c.A
Yes, but in your example A is not semantically a private member of c1, it is more like a local variable of the constructor.
#afrischke gives an example of how to define c1 with an actual private member A (using val fields).
As section 8.6.1.3 of the F# spec states:
The functions and values defined by instance definitions are lexically scoped (and thus implicitly private) to the object being defined.
This is possible and it is widely used, for example, for checking memberwise equality:
type c1 =
member private this.A = 0
interface IEquatable<c1> with
member this.Equals (that: c1) = this.A = that.A
// of course, it can be done in a regular method as well
member this.Equals (that: c1) = this.A = that.A
You just use a directly in an instance method
type c1()
let A = 0
member x.test = A
For a static method this doesn't work as let bindings are slightly different - then you need a class definition like
type c1()
private member x.A = 0
static member test (A:c1) = A.A

Resources