我缺少什么:可能有多个参数的函数组合?

时间:2011-03-26 23:45:34

标签: f# composition function-composition

我理解F#中函数组合的基础知识,例如描述here

但是,也许我错过了一些东西。 >><<运算符似乎是在假定每个函数只接受一个参数的情况下定义的:

> (>>);;
val it : (('a -> 'b) -> ('b -> 'c) -> 'a -> 'c) = <fun:it@214-13>
> (<<);;
val it : (('a -> 'b) -> ('c -> 'a) -> 'c -> 'b) = <fun:it@215-14>

然而,我想做的事情如下:

let add a b = a + b
let double c = 2*c
let addAndDouble = add >> double   // bad!

但即使add的输出属于double输入所需的类型,也会被拒绝。

我知道我可以用一个元组参数重写add:

let add (a,b) = a + b

或者我可以为第一个函数的每个可能参数编写一个新运算符:

let inline (>>+) f g x y = g (f x y)
let doubleAdd = add >>+ double

但它看起来很傻!有没有更好的方式让我错过了?

3 个答案:

答案 0 :(得分:12)

你想要的并不是完全不合理的,但是没有办法在F#的类型系统中指出广义合成运算符的类型。也就是说,没有好的方法来统一

(>>) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c

(>>+) : ('a -> 'b -> 'c) -> ('c -> 'd) -> 'a -> 'b -> 'd

(更不用说无数更高级的arity版本)。因此,除了定义自己的附加运算符之外别无选择。在实践中,我经常发现以“尖头”样式let f x y = add x y |> double编写的代码比无点/“无意义”let f = add (>>+) double更具可读性。

答案 1 :(得分:4)

查看您在上面发布的>><<的类型。例如:

> (>>);;
val it : (('a -> 'b) -> ('b -> 'c) -> 'a -> 'c) = <fun:it@214-13>

它需要两个函数和一个值('a)并返回另一个值。你需要一些需要两个函数和两个值的东西。因此,>><<都没有正确的类型签名。

你的实施根本不是愚蠢的。只是你的要求并没有在F#的库中开箱即用。要感谢你有一种语言允许你定义自己的运算符,如下所示:)

答案 2 :(得分:3)

如何通过线程化一堆参数?

let add = function x :: y :: t -> x + y :: t
let double = function x :: t -> 2 * x :: t

然后你可以组成任意的arity函数:

let doubleAdd = add >> double

它有效:

> doubleAdd [7; 14]
42

(另见F# Function Composition with multiple input parameters