10

我了解 F# 中函数组合的基础知识,例如,此处所述。

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

> (>>);;
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

但这似乎很愚蠢!我错过了更好的方法吗?

4

3 回答 3

12

您想要的并非完全不合理,但无法在 F# 的类型系统中指示通用组合运算符的类型。也就是没有好办法统一

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

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

(更不用说无限多的更高数量的版本了)。因此,您别无选择,只能定义自己的附加运算符。在实践中,我经常发现以“pointed”样式编写的代码let f x y = add x y |> double比无点/“无意义”更易读let f = add (>>+) double

于 2011-03-27T00:09:51.330 回答
4

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

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

它接受两个函数和一个值 ( 'a) 并返回另一个值。您需要具有两个函数和 2 个值的东西。因此,两者>><<没有正确的类型签名。

你的实现一点也不傻。只是您的要求在 F# 的库中并不是开箱即用的。感谢您拥有一种允许您像这样定义自己的运算符的语言:)

于 2011-03-27T00:02:27.023 回答
4

如何通过线程堆栈的参数?

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# 函数组合

于 2011-04-21T02:22:18.450 回答