Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# Partially apply the second argument

in F# if I take a function that takes two arguments, for example, mod (%):

13 % 10
// val it : int = 3

which is the same as

(%) 13 10
// val it : int = 3

is there any way to write it in the pipe notation, currying the 13?

Obviously, the “two-argument function” is actually a one-argument function that returns an intermediate function. So can pipe

10 |> (%) 13
// val it : int = 3

However, I need the other way around, i.e. pipe the first argument 13, having the second argument 10 partially applied, but not the first one.

Is there anything in the language that helps to do that, without creating extra lambdas every time, i.e. to avoid the following?

13 |> (fun x -> x % 10)
like image 966
Ilya Kharlamov Avatar asked Aug 07 '18 15:08

Ilya Kharlamov


4 Answers

There is no built-in, standard way to do this. Moreover, due to how function application works, it's impossible to do so: as soon as you write (%) 13, you've already applied the first argument, because function application has the highest and non-configurable precedence in F#.

You can, if course, make yourself a special function to produce a "weird" function application - one that would apply the second argument and leave a hole for the first:

let ap f x = fun y -> f y x

And then:

let x = 13 |> ap (%) 10
> x : int = 3

Incidentally, the function ap is a semi-standard occurrence in ML languages, and is usually called flip, because what it does is "flipping" the order of the arguments:

let flip f x y = f y x

Or, you can even make it into an operator:

let (-*-) = flip

And then:

let x = 13 |> (%) -*- 10
> x : int = 3

However, this sort of trickery gets unreadable very quickly. In practice, it is far more preferable to just declare a function that does what you need:

let mod10 x = x % 10

And then:

let x = 13 |> mod10

Or, if you really need it to be very general:

let mod' x y = y % x

And then:

let x = 13 |> mod' 10
like image 74
Fyodor Soikin Avatar answered Oct 20 '22 01:10

Fyodor Soikin


You can write a combinator that will do this for any function of two arguments:

let inline flip f y x = f x y

This can be used as:

13 |> flip (%) 10
like image 4
Mankarse Avatar answered Oct 20 '22 01:10

Mankarse


F# already contains an operator that will do what you want, namely <|:

10 |> (%) <| 13;;
val it : int = 10

This is equivalent to

(10 |> (%)) 13;;
val it : int = 10
like image 2
Soldalma Avatar answered Oct 20 '22 03:10

Soldalma


K, you are looking for a flip

let flip f a b = f b a
like image 1
Terrance Avatar answered Oct 20 '22 03:10

Terrance