Можно ли это выразить в бесточечном стиле?

Учитывая следующее выражение для суммирования IEnumerable чисел:

let sum l = l |> Seq.reduce(+)  //version a

можно ли устранить аргумент -- вот так?

let sum = Seq.reduce(+)    //version b

Я получаю сообщение об ошибке от компилятора F# (FS0030), и я, кажется, припоминаю, что видел что-то о «эта-преобразовании», но, к сожалению, мои знания о лямбда-вычислении слишком ограничены, чтобы понять, как происходит эта-преобразование.

Можно ли устранить аргумент, как в варианте б?

Не мог бы кто-нибудь указать мне на литературу, в которой объясняется преобразование эта и как оно будет задействовано в этом конкретном фрагменте кода?

FS0030:

стандартный ввод (1,5): ошибка FS0030: ограничение значения. Предполагается, что значение 'sum' имеет общий тип val sum : ('_a -> int) when '_a :> seq Либо сделайте аргументы 'sum' явными, либо, если вы не хотите, чтобы оно было универсальным, добавить аннотацию типа.


person Onorio Catenacci    schedule 01.10.2013    source источник
comment
Что делает l в версии a? Не могли бы вы напомнить нам (в теле вопроса), что такое FS0030?   -  person Ramon Snir    schedule 01.10.2013
comment
Вы имели в виду let sum l = Seq.reduce (+) l для версии a?   -  person petebu    schedule 01.10.2013
comment
Ну, как вы можете видеть из ошибки (и, вероятно, знаете), F# не допускает универсальных значений. Бесточечный стиль ограниченно поддерживается в F#.   -  person Ramon Snir    schedule 01.10.2013
comment
@petebu спасибо - код исправлен.   -  person Onorio Catenacci    schedule 01.10.2013


Ответы (3)


«Эта-преобразование» просто означает добавление или удаление аргумента. Проблема, с которой вы столкнулись, называется ограничением стоимости. В языках ML значение, объявленное как значение, т.е. объявленный без явных аргументов, не может иметь универсальный тип, даже если он имеет функциональный тип. Здесь приведена соответствующая литература. Идея состоит в том, чтобы не допустить, чтобы ячейка ссылки содержала значения разных типов. Например, без ограничения значения будет разрешена следующая программа:

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, если вы не хотите, чтобы функция была универсальной, вы можете добавить сигнатуру типа и использовать бесточечный стиль.

person Tarmil    schedule 01.10.2013
comment
Можно просто сказать так: функции в языках ML могут быть замыканиями, и, поскольку ML статически типизирован, вы должны устранить неоднозначность типов в среде ссылок перед использованием. - person N_A; 01.10.2013

Вы можете сделать это в стиле без точек, но вам нужно добавить аннотацию (мономорфного) типа:

let sum : int seq -> int = Seq.reduce (+)
person kvb    schedule 01.10.2013
comment
Спасибо @kvb; Мне также было интересно, может ли кто-нибудь указать мне немного больше информации о преобразовании эта. - person Onorio Catenacci; 01.10.2013

Бесточечная функция - это значение.
Как говорят другие ответы, 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
person bytebuster    schedule 01.10.2013
comment
Интересная мысль - добавление встроенного в функцию. - person Onorio Catenacci; 01.10.2013