6

我刚刚学习 F#,在tryfsharp.org玩游戏时,我注意到如果我更改此代码:

[0..100]
|> List.sum

["A"; "B"; "D"]
|> List.sum

我收到以下错误:

The type 'string' does not support the operator 'get_Zero'

这是您可以在浏览器中运行/修改的脚本,尽管它似乎只适用于我的 IE!)

当我检查List.sum 的定义时;它说该类型必须有一个名为 Zero 的静态成员。这似乎解释了错误;除了我在 int 上看不到任何名为 Zero 的成员!

所以; 这个适用于整数的零成员在哪里?如果我键入 intellisense ,我看不到它,也看不到int.docs 它说 int 只是一个 .NET System.Int32 (它似乎没有静态零属性)。

(注意:它确实在错误中说“操作员”而不是“成员”;这可能是相关的;尽管 List.sum 定义确实只是说“成员”)。

4

2 回答 2

10

挖掘 F# 源代码,List.sum(和 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

另一方面,F# 编译器在查询零成员之前构建一个表来查找所有内置数字类型的零值。相关位在这一行和下面的代码片段中。

    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在字符串类型的情况下没有多大意义。

于 2013-06-22T13:35:16.177 回答
3

一般来说,F# 规范是查找此类信息的最佳位置。我相信这应该在第 14.5.4.1 节(成员约束的解决方案模拟)中进行介绍,但看起来Zero实际上并没有在其中提到,这几乎可以肯定是一个规范错误。

于 2013-10-29T13:55:57.280 回答