开发者

F# passing an operator with arguments to a function

开发者 https://www.devze.com 2022-12-12 16:36 出处:网络
Can you pass in an operation like \"divide by 2\" or \"subtract 1\" using just a partially applied operator, where \"add 1\" looks like this:

Can you pass in an operation like "divide by 2" or "subtract 1" using just a partially applied operator, where "add 1" looks like this:

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

What's happening is 1 is being applied to (+) as it's first argument, and the list item is being applied as the sec开发者_运维技巧ond argument. For addition and multiplication, this argument ordering doesn't matter.

Suppose I want to subtract 1 from every element (this will probably be a common beginners mistake):

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

1 is applied to the (-) as its first argument, so instead of (list_item - 1), I get (1 - list_item). I can rewrite it as adding negative one instead of subtracting positive one:

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

I'm looking for a more expressive way to write it, something like ((-) _ 1), where _ denotes a placeholder, like in the Arc language. This would cause 1 to be the second argument to -, so in List.map, it would evaluate to list_item - 1. So if you wanted to map divide by 2 to the list, you could write:

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

Can this be done or do I have to use (fun x -> x/2)? It seems that the closest we can get to the placeholder syntax is to use a lambda with a named argument.


You could write a flip function, something like:

let flip f x y = f y x

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

I may have the syntax wrong, I'm not terribly fluent in F#.


There are no 'operation sections' in F#, a la Haskell, nor placeholder arguments (apparently a la Arc). You can use a 'flip' combinator as suggested in another answer to reverse the order of arguments and then partially apply the first (now second) argument.

But I would just use

fun x -> x / 2

Unless you're playing code-golf, I don't think trying to shave another few characters off here buys you anything.


The flip-solution suggested by Logan Capaldo can also be written using a operator (here >.):

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

Or if you prefer the operands the other way around:

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

Edit: Using an operator that "looks more like a placeholder" (here >-<) gets you very close to your suggested syntax:

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

'_' is unfortunatly(?) not a valid operator symbol in F#.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号