Что / где находится get_Zero в F# int?
Я только изучаю F#, и во время игры на http://www.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. Это, кажется, объясняет ошибку; за исключением того факта, что я не вижу ни одного члена с именем Zero на int!
Так; где этот нулевой член, который относится к целым? Я не могу видеть это в intellisense, если я печатаю int.
ни в документах, где говорится, что int - это просто.NET System.Int32 (который , похоже, не обладает статическим нулевым свойством).
(примечание: в сообщении об ошибке говорится "оператор", а не "участник"; это может быть связано; хотя определение List.sum просто говорит "участник").
2 ответа
Копаясь в исходном коде 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
не имеет особого смысла в случае строкового типа.
Вообще говоря, спецификация F# - лучшее место для поиска такого рода информации. Я считаю, что это должно быть рассмотрено в разделе 14.5.4.1 (Моделирование решений для ограничений членов), но похоже, что Zero
там на самом деле не упоминается, что почти наверняка является ошибкой спецификации.