F# record member evaluation

非 Y 不嫁゛ 提交于 2019-12-22 03:22:50

问题


Why is t.b evaluated on every call? And is there any way how to make it evaluate only once?

type test =
  { a: float }
  member x.b =
    printfn "oh no"
    x.a * 2.

let t = { a = 1. }
t.b
t.b

回答1:


It's a property; you're basically calling the get_b() member.

If you want the effect to happen once with the constructor, you could use a class:

type Test(a:float) =
    // constructor
    let b =   // compute it once, store it in a field in the class
        printfn "oh no"
        a * 2.
    // properties
    member this.A = a
    member this.B = b



回答2:


An alternative version of Brian's answer that will evaluate b at most once, but won't evaluate it at all if B is never used

type Test(a:float) =
    // constructor
    let b = lazy
                 printfn "oh no"
                 a * 2.
    // properties
    member this.A = a
    member this.B = b.Value



回答3:


In response to your comments in Brian's post, you can fake copy-and-update record expressions using optional/named args. For example:

type Person(?person:Person, ?name, ?age) =

    let getExplicitOrCopiedArg arg argName copy =
        match arg, person with
        | Some(value), _ -> value
        | None, Some(p) -> copy(p)
        | None, None -> nullArg argName

    let name = getExplicitOrCopiedArg name "name" (fun p -> p.Name)
    let age = getExplicitOrCopiedArg age "age" (fun p -> p.Age)

    member x.Name = name
    member x.Age = age

let bill = new Person(name = "Bill", age = 20)
let olderBill = new Person(bill, age = 25)

printfn "Name: %s, Age: %d" bill.Name bill.Age
printfn "Name: %s, Age: %d" olderBill.Name olderBill.Age



回答4:


The previous responses suggest switching to a class, instead of using a record. If you want to stay with records (for their simple syntax and immutability), you can take this approach:

type test =
    { a : float
      b : float }
    static member initialize (t: test) =
        { t with b = t.a * 2. }

This is useful if the instance of test is created by another library (like a data provider from a web service or database). With this approach, you must remember to pass any instance of test that you receive from that API through the initialize function before using it in your code.



来源:https://stackoverflow.com/questions/2873125/f-record-member-evaluation

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!