给定一个具有任意参数类型和数字的任意函数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
之前将每个函数联合起来。在这个玩具示例中,f
和g
都有一个参数,因此解决方案很简单,但在实际情况下,不同的函数具有不同数量的参数。
自从写下这些问题以来,我一直咬紧牙关,写了一个带有15个通用参数的Funcs
庞然大物。
答案 0 :(得分:4)
假设,您创建了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 = ()