Given the following expression to sum an IEnumerable of numbers:
let sum l = l |> Seq.reduce(+) //version a
is it possible to eliminate
"Eta conversion" simply means adding or removing the argument. The problem you are hitting is called value restriction. In ML languages, a value declared as a value, ie. declared without explicit arguments, cannot have a generic type, even if it has a function type. Here is some relevant literature. The idea is to prevent a ref cell from holding values of different types. For example, without value restriction, the following program would be allowed:
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!!!
As kvb said, if you do not intend the function to be generic, then you can add a type signature and use point-free style.
A point-free function is a value.
As other answers say, F# does not allow generic values. However, it perfectly allows generic functions. Let's convert sum
into a function by adding a fake unit
parameter:
let sum_attempt1() = Seq.reduce (+)
let v1 = [1.0; 2.0] |> sum() // float
// inferred by first usage:
// val sum_attempt1: unit -> (seq<float> -> float)
This works, although it is not yet generic. Marking the function inline
does the trick:
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
You can do it in point free style, but you need to add a (monomorphic) type annotation:
let sum : int seq -> int = Seq.reduce (+)