11

您能否仅使用部分应用的运算符传入“除以 2”或“减 1”之类的运算,其中“加 1”如下所示:

List.map ((+) 1) [1..5];;  //equals [2..6]
// instead of having to write: List.map (fun x-> x+1) [1..5]

发生的事情是 1 作为第一个参数应用于 (+),而列表项作为第二个参数应用。对于加法和乘法,此参数排序无关紧要。

假设我想从每个元素中减去 1(这可能是初学者的常见错误):

List.map ((-) 1) [1..5];;  //equals [0 .. -4], the opposite of what we wanted

1 应用于 (-) 作为它的第一个参数,所以(list_item - 1)我得到. 而不是(1 - list_item). 我可以将其重写为添加负数而不是减去正数:

List.map ((+) -1) [1..5];;
List.map (fun x -> x-1) [1..5];; // this works too

我正在寻找一种更具表现力的方式来编写它,例如((-) _ 1),其中_表示占位符,就像在 Arc 语言中一样。这将导致1成为 的第二个参数-,因此在 List.map 中,它将评估为list_item - 1。所以如果你想映射divide by 2到列表,你可以写:

List.map ((/) _ 2) [2;4;6] //not real syntax, but would equal [1;2;3] 
List.map (fun x -> x/2) [2;4;6] //real syntax equivalent of the above

可以这样做还是我必须使用(fun x -> x/2)?似乎最接近占位符语法的方法是使用带有命名参数的 lambda。

4

3 回答 3

16

您可以编写一个翻转函数,例如:

let flip f x y = f y x

List.map (flip (-) 1) [2;4;6]

我可能语法错误,我对 F# 不是很流利。

于 2009-11-30T03:02:38.077 回答
10

F# 中没有“操作部分”、la Haskell,也没有占位符参数(显然是 la Arc)。您可以使用另一个答案中建议的“翻转”组合器来反转参数的顺序,然后部分应用第一个(现在是第二个)参数。

但我会用

fun x -> x / 2

除非您正在玩代码高尔夫,否则我认为尝试在这里剃掉另外几个角色不会给您带来任何好处。

于 2009-11-30T03:09:31.323 回答
10

Logan Capaldoflip建议的解决方案也可以使用运算符(此处)编写:>.

let (>.) x f = (fun y -> f y x)
List.map (1 >. (-)) [2;4;6]

或者,如果您更喜欢相反的操作数:

let (>.) f x = (fun y -> f y x)
List.map ((-) >. 1) [2;4;6]

编辑:使用“看起来更像占位符”的运算符(此处>-<)让您非常接近建议的语法:

List.map ((-) >-< 1) [2;4;6]

'_' 不幸的是(?)不是F# 中的有效运算符符号

于 2009-11-30T08:53:27.993 回答