是否可以复合功能但保持currying?

时间:2013-07-19 14:37:05

标签: f#

例如,我可以这样做:

let mutable divide = fun (a,b) -> a / b
let checkZero (a,b) = if b = 0 then failwith "wrong" else (a,b)
divide <- checkZero >> divide

divide (5,3)

但如果我想形成一个currying函数怎么办:

let mutable divide = fun a b -> a / b
let checkZero a b = if b = 0 then failwith "wrong" else ... // How return
                                                     // the two argument
divide <- checkZero >> divide

divide 5 3

我能这样做吗?

3 个答案:

答案 0 :(得分:2)

>>的类型是:

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

因此checkZerodivide应遵守类型:'a -> 'b

答案 1 :(得分:2)

不是直接的,而是做这样的事情:

let curry f a b = f (a,b)
let uncurry f (a,b) = f a b

let mutable divide = fun a b -> a / b
let checkZero a b = if b = 0 then failwith "wrong" else (a,b)

divide <- let f = (uncurry checkZero) >> (uncurry divide) in curry f

答案 2 :(得分:1)

所以你有两个谓词,checkZerodivide,并且你想对这两个谓词应用相同的参数(一个元组)。

就像在this question中一样:将checkZero包装到一个组合器中,该组合器将忽略返回值并返回原始参数。请注意,需要时将抛出异常。这种组合器在WebSharper中定义:

let ( |>! ) x f = f x; x
// Usage:
let checkZero a b = if b = 0 then failwith "wrong" else ()
let ret = (5,3) |>! checkZero |> divide

仅当checkZero返回unit时才会有效。如果它应该返回其他内容(并且应该强制忽略返回值),那么这个定义将起到作用:

let ( |>!! ) x f = ignore(f x); x
// Usage:
let checkZero a b = if b = 0 then failwith "wrong" else "42"
let ret = (5,3) |>!! checkZero |> divide

上面的解决方案似乎是最干净的,因为它不需要修改谓词。组合器可以在整个项目中重复使用。