2013-10-01 4 views
4

Учитывая следующее выражение просуммировать IEnumerable цифр:Можно ли это выразить в виде свободного стиля?

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

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

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

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

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

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

FS0030:

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

+0

Что делает 'l' в версии a? Не могли бы вы напомнить нам (в вопросе), что такое 'FS0030'? –

+2

Вы имели в виду 'let sum l = Seq.reduce (+) l' для версии a? – petebu

+0

Ну, как вы можете видеть из ошибки (и, вероятно, знаете), F # не допускает общих значений. Непосредственный стиль поддерживается только в F #. –

ответ

7

«преобразование Eta» просто означает добавление или удаление аргумент. Проблема, которую вы нажимаете, называется ограничением значений. В языках ML - значение, объявленное как значение, т.е. объявленный без явных аргументов, не может иметь общий тип, даже если он имеет тип функции. Here - соответствующая литература. Идея состоит в том, чтобы помешать 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, если вы не собираетесь функция быть универсальной, то вы можете добавить подпись типа и использовать точечный свободный стиль.

+1

Возможно, просто заявлено как: функции на языках ML могут быть закрытыми, и поскольку ML статически типизирован, вы должны устранить неоднозначность типов в ссылочной среде перед использованием. – mydogisbox

5

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

let sum : int seq -> int = Seq.reduce (+) 
+0

Спасибо @kvb; Мне также было интересно, может ли кто-нибудь указать мне немного больше информации о преобразовании эта. –

4

Точечная функция - это значение.
Как другие ответы говорят, что 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 
+0

Интересная мысль - добавление встроенной функции. –