I understand the basics of function composition in F#, as, for example, described here.
Maybe I am missing something, though. The >>
and <<
operators seem to have been defined with the assumption that each function only takes one argument:
> (>>);;
val it : (('a -> 'b) -> ('b -> 'c) -> 'a -> 'c) = <fun:it@214-13>
> (<<);;
val it : (('a -> 'b) -> ('c -> 'a) -> 'c -> 'b) = <fun:it@215-14>
What I'd like to do, however, is something like the following:
let add a b = a + b
let double c = 2*c
let addAndDouble = add >> double // bad!
But even though add
's output is of the type required for double
's input, that is rejected.
I know that I can rewrite add with one tuple argument:
let add (a,b) = a + b
Or I can write a new operator for every number of possible arguments to the first function:
let inline (>>+) f g x y = g (f x y)
let doubleAdd = add >>+ double
But it seems silly! Is there a better way that I've missed?
What you want isn't totally unreasonable, but there would be no way to indicate the type of a generalized composition operator within F#'s type system. That is, there's no good way to unify
(>>) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c
and
(>>+) : ('a -> 'b -> 'c) -> ('c -> 'd) -> 'a -> 'b -> 'd
(not to mention the infinitely many higher arity versions). Therefore, you have no alternative but to define your own additional operators. In practice, I often find code written in the "pointed" style let f x y = add x y |> double
more readable than the point-free/"pointless" let f = add (>>+) double
anyway.