为什么在每次通话中评估t.b?有没有办法让它只评估一次?F#记录成员评估
type test =
{ a: float }
member x.b =
printfn "oh no"
x.a * 2.
let t = { a = 1. }
t.b
t.b
为什么在每次通话中评估t.b?有没有办法让它只评估一次?F#记录成员评估
type test =
{ a: float }
member x.b =
printfn "oh no"
x.a * 2.
let t = { a = 1. }
t.b
t.b
这是一个属性;你基本上打电话给get_b()
成员。
如果你想要的效果与构造,一旦发生,你可以使用一个类:
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
你是对的,但使用类我失去的东西就像c = {t with a = 4.},对吧? – 2010-05-20 12:55:29
是的,但您可以使用可选参数编写构造函数,并获得非常相似的效果。 – Brian 2010-05-20 19:56:38
我不明白你的想法。想象一下,我有一个带有10个参数的构造函数的Record,如{a:float; b:float,c:float ...}。从旧的创建一个新的记录完成{旧= c = 5}。如何在不重写构造函数中的所有参数的情况下对类进行相同操作? – 2010-05-21 10:55:10
Brian的回答的另一个版本,将最多一次评估b
,但不会对其进行评估如果全部是B
从未使用
type Test(a:float) =
// constructor
let b = lazy
printfn "oh no"
a * 2.
// properties
member this.A = a
member this.B = b.Value
在回答您的意见Brian的帖子,你可以通过选配的名为/ ARGS假冒复制和更新记录表达式。例如:
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
以前的答案建议切换到类而不是使用记录。如果你想留在记录(其简单的语法和不变性),你可以采取这种做法:
type test =
{ a : float
b : float }
static member initialize (t: test) =
{ t with b = t.a * 2. }
如果是由其他库创建的test
实例(如来自Web的数据提供者,这是有用服务或数据库)。使用这种方法,您必须记住在您的代码中使用它之前,通过初始化函数从该API接收到的任何test
实例。
令人失望的是,F#语言不支持不可变记录的一次计算值。我认为并发症是如果'a'被标记为可变的。 – Wally 2014-11-03 01:43:11