Можно ли это выразить в стиле free point?
Дано следующее выражение для суммирования IEnumerable чисел:
let sum l = l |> Seq.reduce(+) //version a
Можно ли устранить аргумент - как так?
let sum = Seq.reduce(+) //version b
Я получаю сообщение об ошибке от компилятора F# (FS0030), и мне кажется, что я вспомнил, что видел что-то об "eta-преобразовании", но, к сожалению, мои знания о lambda calc слишком ограничены, чтобы понять, как происходит eta-преобразование.
Можно ли исключить аргумент, как в версии b?
Кто-нибудь, пожалуйста, укажите мне литературу, которая объясняет eta-преобразование и как оно вступит в игру в этом конкретном фрагменте кода?
FS0030:
стандартный ввод (1,5): ошибка FS0030: ограничение значения. Значение 'sum' было выведено для того, чтобы иметь универсальный тип val sum: ('_a -> int), когда'_a:> seq Либо сделать аргументы для 'sum' явными, либо, если вы не намереваетесь сделать его универсальным, добавить аннотацию типа.
3 ответа
"Eta преобразование" просто означает добавление или удаление аргумента. Проблема, которую вы затрагиваете, называется ограничением стоимости. В языках ML значение, объявленное как значение, т.е. объявленный без явных аргументов, не может иметь универсальный тип, даже если он имеет тип функции. Вот некоторая соответствующая литература. Идея состоит в том, чтобы в ячейке ref не содержались значения разных типов. Например, без ограничения значения будет разрешена следующая программа:
let f : 'a -> 'a option =
let r = ref None
fun x ->
let old = !r
r := Some x
old
f 3 // r := Some 3; returns None : int option
f "t" // r := Some "t"; returns Some 3 : string option!!!
Как сказал kvb, если вы не хотите, чтобы функция была универсальной, вы можете добавить сигнатуру типа и использовать стиль без точек.
Вы можете сделать это в стиле без точек, но вам нужно добавить (мономорфную) аннотацию типа:
let sum : int seq -> int = Seq.reduce (+)
Бессмысленная функция - это значение.
Как говорят другие ответы, F# не допускает общих значений. Тем не менее, он прекрасно допускает общие функции. Давайте конвертировать sum
в функцию, добавив подделку unit
параметр:
let sum_attempt1() = Seq.reduce (+)
let v1 = [1.0; 2.0] |> sum() // float
// inferred by first usage:
// val sum_attempt1: unit -> (seq<float> -> float)
Это работает, хотя это еще не является общим. Маркировка функции inline
делает трюк:
let inline sum() = Seq.reduce (+)
// val sum: unit -> (seq<'a> -> 'a)
// Use
let v1 = [1; 2] |> sum() // int
let v2 = [1.0; 2.0] |> sum() // float
let v3 = ["foo"; "bar"] |> sum() // string