问题
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?
回答1:
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.
回答2:
Look at the types of >>
and <<
that you posted above. eg:
> (>>);;
val it : (('a -> 'b) -> ('b -> 'c) -> 'a -> 'c) = <fun:it@214-13>
It takes two functions and a value ('a
) and returns another value. You need something that takes two functions and 2 values. Hence, both >>
and <<
don't have the correct type signature.
Your implementation isn't silly at all. It's just that your requirement doesn't come out of the box in F#'s libraries. Be thankful that you have a language which allows you to define your own operators like this :)
回答3:
How about threading a stack of arguments through?
let add = function x :: y :: t -> x + y :: t
let double = function x :: t -> 2 * x :: t
Then you can compose arbitrary arity functions:
let doubleAdd = add >> double
And it works:
> doubleAdd [7; 14]
42
(see also F# Function Composition with multiple input parameters)
来源:https://stackoverflow.com/questions/5446199/what-am-i-missing-is-function-composition-with-multiple-arguments-possible