It seems to me that all of these are related. What is the difference?
Piping is used to perform a sequence of operations on some value (just like piping in Unix). The input to each function is the output of the previous function. Obviously this requires each function take a single arg.
Composition (<<
/ >>
) is similar in that it calls two functions in sequence (i.e., the output of the first is the input to the second) but it returns a function instead of immediately invoking the sequence.
Currying creates a new function by applying 1 to N-1 args to a function of N args
So, composition and currying are used to create functions whereas piping is used for invocation. Composition and currying differ in the way they create new functions (by applying args vs chaining).
In addition to what Daniel wrote, there is a very close correspondence between piping (the |>
and <|
operators) and function composition (the >>
and <<
operators).
When you use piping to pass some data to a seqence of functions:
nums |> Seq.filter isOdd
|> Seq.map square
|> Seq.sum
... then this is equivalent to passing the input to a function obtained using function composition:
let composed =
Seq.filter isOdd
>> Seq.map square
>> Seq.sum
composed nums
In practice, this often means that you can replace function declaration that uses piping on the argument with a composition of functions (and use the fact that functions can be used as values). Here is an example:
// Explicit function declaration
foo (fun x -> x |> bar |> goo)
// Equivalent using function composition
foo (bar >> goo)