Можно ли это выразить в стиле 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
Другие вопросы по тегам