F# 中静态成员的不一致(显然)行为
Inconsistent (apparently) behaviour with static members in F#
以下前 2 个 F# 片段得到不同的结果,但我发现这有点不一致,尽管我知道成员和值具有不同的语义。我希望它们都得到相同的结果(第二个,因为它们具有相似的值语法)。
恕我直言,第三个片段明确定义了 get 方法,应该与第一个片段有所区别。
我一个人吗?
let mutable b = 0
type A = A with
static member B =
b <- b + 1
b
printfn "%d" A.B
printfn "%d" A.B
printfn "%d" A.B
//1
//2
//3
let mutable b = 0
type A = A
let _b =
b <- b + 1
b
type A with
static member B = _b
printfn "%d" A.B
printfn "%d" A.B
printfn "%d" A.B
//1
//1
//1
let mutable b = 0
type A = A with
static member B
with get() =
b <- b + 1
b
printfn "%d" A.B
printfn "%d" A.B
printfn "%d" A.B
//1
//2
//3
编辑
我同意 Tomas 的观点,语法有点误导。但是我可以看到困境在哪里:虽然值语法是 F#/functional,但成员符号必须复制 .NET/Object 定向行为。
对于那些感兴趣的,值行为静态成员可以是一个模式:
type MyType = MyType
let private myValueBehavingStaticPropertyValue =
... potentially heavy workflow
type MyType with
static member MyValueBehavingStaticProperty = myValueBehavingStaticPropertyValue
有了这个,'potentially heavy workflow'就不会在我们每次读到属性
的时候重复了
The following first 2 F# snippets get different results, but I find this a little inconsistent, even though I understand that members and values have different semantics. I would expect both of them getting the same results (the second one, as they have a similar value syntax).
您期望计算 _b
会导致它重新计算自身,但这不是 F# 中值的计算方式。如果我定义 let x = 12
它不会在我每次访问它时重新评估 x
是什么。
这就是它总是打印 1
的原因。当 _b
第一次被访问时,它被评估一次,就是这样。
IMHO the third snippet, which explicitly defines a get method, should be differentiated from the first.
为什么?这与第一个片段没有什么不同。 F# 属性 定义如下:
type A =
static member X = 12
使用 getter 编译,就像您明确定义它一样。
在此代码段中:
let mutable b = 0
type A = A
let _b =
b <- b + 1
b
type A with
static member B = _b
printfn "%d" A.B
printfn "%d" A.B
printfn "%d" A.B
_b
得到值 1,不管它后面的所有内容。 _b
永远不会重新评估。因此,虽然 属性 A.B 本身一直在重新评估,但它只会 return 已经设置好的值 _b
。
我觉得你的问题很好。 static 属性 的定义在语法上与值的定义非常相似 - 所以我明白为什么你认为两者的行为应该相同。
这有点误导,因为在 senes 的背后,属性有一个 getter 方法,每次访问 属性 时都会计算该方法。作为一个最小的例子,在下面,访问 A1.B
两次打印“hi”两次:
type A1 = A1 with
static member B =
printfn "hi"
A1.B; A1.B
实际上在 F# 中有一个更详细的属性语法,它揭示了正在发生的事情——B
实际上是由编译代码调用的 get()
方法支持的事实幕后花絮:
type A2 = A2 with
static member B
with get() = printfn "hi"
A2.B; A2.B
现在,您实际上永远不会这样做,但您甚至可以直接调用该方法(对 IntelliSense 隐藏):
A2.get_B(); A2.get_B()
您的第二个版本不等同于第一个或第三个版本。这是:
let mutable b = 0
type A = A
let _b () =
b <- b + 1
b
type A with
static member B = _b ()
printfn "%d" A.B
printfn "%d" A.B
printfn "%d" A.B
//1
//2
//3
_b
在这里被标识为 function 而不是 value (如您的情况),因此被调用每次通过 A.B
调用静态成员时。所以我想说这种明显的不一致只有在混淆了 values(只计算一次)和 functions(它们是仅在每次调用它们时进行评估)。
以下前 2 个 F# 片段得到不同的结果,但我发现这有点不一致,尽管我知道成员和值具有不同的语义。我希望它们都得到相同的结果(第二个,因为它们具有相似的值语法)。
恕我直言,第三个片段明确定义了 get 方法,应该与第一个片段有所区别。
我一个人吗?
let mutable b = 0
type A = A with
static member B =
b <- b + 1
b
printfn "%d" A.B
printfn "%d" A.B
printfn "%d" A.B
//1
//2
//3
let mutable b = 0
type A = A
let _b =
b <- b + 1
b
type A with
static member B = _b
printfn "%d" A.B
printfn "%d" A.B
printfn "%d" A.B
//1
//1
//1
let mutable b = 0
type A = A with
static member B
with get() =
b <- b + 1
b
printfn "%d" A.B
printfn "%d" A.B
printfn "%d" A.B
//1
//2
//3
编辑
我同意 Tomas 的观点,语法有点误导。但是我可以看到困境在哪里:虽然值语法是 F#/functional,但成员符号必须复制 .NET/Object 定向行为。
对于那些感兴趣的,值行为静态成员可以是一个模式:
type MyType = MyType
let private myValueBehavingStaticPropertyValue =
... potentially heavy workflow
type MyType with
static member MyValueBehavingStaticProperty = myValueBehavingStaticPropertyValue
有了这个,'potentially heavy workflow'就不会在我们每次读到属性
的时候重复了The following first 2 F# snippets get different results, but I find this a little inconsistent, even though I understand that members and values have different semantics. I would expect both of them getting the same results (the second one, as they have a similar value syntax).
您期望计算 _b
会导致它重新计算自身,但这不是 F# 中值的计算方式。如果我定义 let x = 12
它不会在我每次访问它时重新评估 x
是什么。
这就是它总是打印 1
的原因。当 _b
第一次被访问时,它被评估一次,就是这样。
IMHO the third snippet, which explicitly defines a get method, should be differentiated from the first.
为什么?这与第一个片段没有什么不同。 F# 属性 定义如下:
type A =
static member X = 12
使用 getter 编译,就像您明确定义它一样。
在此代码段中:
let mutable b = 0
type A = A
let _b =
b <- b + 1
b
type A with
static member B = _b
printfn "%d" A.B
printfn "%d" A.B
printfn "%d" A.B
_b
得到值 1,不管它后面的所有内容。 _b
永远不会重新评估。因此,虽然 属性 A.B 本身一直在重新评估,但它只会 return 已经设置好的值 _b
。
我觉得你的问题很好。 static 属性 的定义在语法上与值的定义非常相似 - 所以我明白为什么你认为两者的行为应该相同。
这有点误导,因为在 senes 的背后,属性有一个 getter 方法,每次访问 属性 时都会计算该方法。作为一个最小的例子,在下面,访问 A1.B
两次打印“hi”两次:
type A1 = A1 with
static member B =
printfn "hi"
A1.B; A1.B
实际上在 F# 中有一个更详细的属性语法,它揭示了正在发生的事情——B
实际上是由编译代码调用的 get()
方法支持的事实幕后花絮:
type A2 = A2 with
static member B
with get() = printfn "hi"
A2.B; A2.B
现在,您实际上永远不会这样做,但您甚至可以直接调用该方法(对 IntelliSense 隐藏):
A2.get_B(); A2.get_B()
您的第二个版本不等同于第一个或第三个版本。这是:
let mutable b = 0
type A = A
let _b () =
b <- b + 1
b
type A with
static member B = _b ()
printfn "%d" A.B
printfn "%d" A.B
printfn "%d" A.B
//1
//2
//3
_b
在这里被标识为 function 而不是 value (如您的情况),因此被调用每次通过 A.B
调用静态成员时。所以我想说这种明显的不一致只有在混淆了 values(只计算一次)和 functions(它们是仅在每次调用它们时进行评估)。