我可以在curried函数上应用运算符,以便它的返回类型是单位而不指定参数的数量吗?

时间:2014-06-23 12:48:59

标签: f#

给定一个具有任意参数类型和数字的任意函数func我希望得到一个返回单位的函数 - func,忽略返回值。可以将其视为纯粹副作用函数的投影。如果func接受一个参数(或者它是一个未经证实的形式),则它只是func>>ignore。显而易见的解决方案是为我们需要的func的每个参数编写一个泛型运算符:

let inline unitise1 f a = f a |> ignore
let inline unitise2 f a b = f a b |> ignore
let inline unitise3 f a b c = f a b c |> ignore
let inline unitise4 f a b c d = f a b c d |> ignore

等。这是混乱和不方便的,因为我们需要每次都计算参数,并且代码不会很好地重构。是否有一种我缺少的语言结构可以让它更清洁?

编辑:我相信这样的运算符会很有用,因为NET泛型比F#静态解析类型参数弱。这就是我的意思。假设我有一个更高阶的函数

let inline higher f g =
    f 7 |> ignore
    g 3 |> ignore

我们可以将任何函数传递给它,只要它的第一个参数是int。所以这将有效:

let add n = n+1
let str (n:int) = n.ToString()
higher add str
higher str add 

特别是,不需要通用类型注释。这就是我们对F#的了解和喜爱。现在,我有一个情况是我需要传递很多(~15)函数作为higher的参数。它们将多次传递给调用链。将它们分组在数据结构中是很自然的。

type Funcs<'R1,'R2,'R3> = {f1:int->'R1;f2:int->'R2;f3:int->'R3}

在达到15个通用参数之前,这很难看。只有在涉及函数时才可以进行类型注释。如果我可以将功能统一起来,我会将higher更改为

let inline higher f g =
    f 7
    g 3

并将使用一个辅助函数,在从它们构建Funcs之前将每个函数联合起来。在这个玩具示例中,fg都有一个参数,因此解决方案很简单,但在实际情况下,不同的函数具有不同数量的参数。

自从写下这些问题以来,我一直咬紧牙关,写了一个带有15个通用参数的Funcs庞然大物。

2 个答案:

答案 0 :(得分:4)

@TomasPetricek是绝对正确的,你无法建立这样的功能。 以下是证据。

假设,您创建了unitise函数,以便以下工作:

// just sample functions with 1, 2, and 3 curried arguments
let f1 a = a
let f2 a b = (a,b)
let f3 a b c = (a,b,c)

let x1 = unitise f1 5             // expected x1:unit
let x2 = unitise f2 5 42          // expected x2:unit
let x3 = unitise f3 5 "foobar" 42 // expected x3:unit

任意数量的curried参数都没有通用,因此您必须在调用(f1 5)之前计算(f2 5 42)unitise等:

let x1 = unitise (f1 5)             // expected x1:unit
let x2 = unitise (f2 5 42)          // expected x2:unit
let x3 = unitise (f3 5 "foobar" 42) // expected x3:unit

因此,unitise等同于ignore

let x3 = ignore (f3 5 "foobar" 42) // expected x3:unit

如果您希望ignore(或unitise)放在语句的最开头,并且为了便于阅读而避免使用括号,请考虑使用高优先级,右关联后管(^<|)

let inline (^<|) f a = f a

然后您的代码将如下所示:

let x1 = ignore ^<| f1 5             // expected x1:unit
let x2 = ignore ^<| f2 5 42          // expected x2:unit
let x3 = ignore ^<| f3 5 "foobar" 42 // expected x3:unit

答案 1 :(得分:2)

这种功能的定义是不连贯的。请记住,在f#中,没有超过1个参数的函数

功能

let f a b = 0

相同
let f a = fun b -> 0

所以它应该是那个

unitize f a b = ()

unitize f a = ()

暗示

() b = ()