我只是在学习F#,在tryfsharp.org玩的时候,我注意到如果我改变了这段代码:
[0..100]
|> List.sum
到
["A"; "B"; "D"]
|> List.sum
我收到以下错误:
The type 'string' does not support the operator 'get_Zero'
(Here's the script that you can run/amend in your browser,虽然它似乎只适用于我的IE!)
当我查看the definition of List.sum时;它说类型必须有一个名为Zero的静态成员。这似乎解释了错误;除了我无法在int上看到任何名为Zero的成员!
因此;这个适用于整数的零成员在哪里?如果我输入int.
,也不能输入the docs,我认为int不仅仅是一个.NET System.Int32(doesn't seem to have一个静态零属性)。< / p>
(注意:它确实在错误中说“运算符”而不是“成员”;这可能是相关的;虽然List.sum定义只是说“成员”)。
答案 0 :(得分:8)
挖掘F#源代码,List.sum (and Seq.sum)正在使用GenericZero:
let inline sum (source: seq< (^a) >) : ^a =
use e = source.GetEnumerator()
let mutable acc = LanguagePrimitives.GenericZero< (^a) >
while e.MoveNext() do
acc <- Checked.(+) acc e.Current
acc
另一方面,在查询Zero成员之前,F#编译器构建一个表来查找所有内置数值类型的零值。相关位在this line和下面的代码片段中。
type GenericZeroDynamicImplTable<'T>() =
static let result : 'T =
// The dynamic implementation
let aty = typeof<'T>
if aty.Equals(typeof<sbyte>) then unboxPrim<'T> (box 0y)
elif aty.Equals(typeof<int16>) then unboxPrim<'T> (box 0s)
elif aty.Equals(typeof<int32>) then unboxPrim<'T> (box 0)
elif aty.Equals(typeof<int64>) then unboxPrim<'T> (box 0L)
elif aty.Equals(typeof<nativeint>) then unboxPrim<'T> (box 0n)
elif aty.Equals(typeof<byte>) then unboxPrim<'T> (box 0uy)
elif aty.Equals(typeof<uint16>) then unboxPrim<'T> (box 0us)
elif aty.Equals(typeof<uint32>) then unboxPrim<'T> (box 0u)
elif aty.Equals(typeof<uint64>) then unboxPrim<'T> (box 0UL)
elif aty.Equals(typeof<unativeint>) then unboxPrim<'T> (box 0un)
elif aty.Equals(typeof<decimal>) then unboxPrim<'T> (box 0M)
elif aty.Equals(typeof<float>) then unboxPrim<'T> (box 0.0)
elif aty.Equals(typeof<float32>) then unboxPrim<'T> (box 0.0f)
else
let pinfo = aty.GetProperty("Zero")
unboxPrim<'T> (pinfo.GetValue(null,null))
static member Result : 'T = result
也就是说,如果您想在用户定义的类型上使用List.sum
,则需要明确定义Zero成员。请注意,Zero
在字符串类型的情况下没有多大意义。
答案 1 :(得分:3)
一般来说,F# specification是查找此类信息的最佳位置。我认为这应该在第14.5.4.1节(模拟成员约束的解决方案)中介绍,但看起来Zero
实际上没有提到,这几乎肯定是规范错误。