Reverse Curry?

I would like to write functions in a certain way. Please consider these 2 functions in pseudo-code (not F #)

F1 = x + y F2 = F1 * 10 // note I did not specify arguments for F1, 'reverse curry' for lack of a better word 

What I would like to do for F # is to find out that since

 let F1 xy = x + y //val F1 : int -> int -> int 

the code let F2 = F1 * 10 would give me the same signature as F1: val F2 : int -> int -> int , and calling F2 2 3 would result in 50: (2 + 3) * 10. That would be pretty cleverly ...

What is happening is completely different. The first line goes as expected:

 let F1 xy = x + y //val F1 : int -> int -> int 

but when I add the second line let F2 = F1 * 10 , it discards F #. He complains that the type int does not match the type 'a -> 'b -> 'c and F1 now requires member ( + ) .

I could, of course, describe it as follows:

 let F1(x, y) = x + y let F2(x, y) = F1(x, y) * 10 

But now I could use C #, we are not that far already. Corrupted arguments break a lot of F #'s elegance. Also my real functions F1 and F2 have a lot more arguments than just 2, so that makes me cross, exactly what I wanted to avoid using F #. To say so would be much more natural:

 let F1 xy = x + y let F2 = F1 * 10 

Is there a way (almost) to do this?

Extra credits: what exactly happens with these error messages? Why does the second line let F2 = F1 * 10 change the typing on the first?

Thanks for your thoughts,

Geert Yang

Update Two jurors who (almost) do what is described.

One using a tuple. The second line looks a little freaky first, works great. A minor flaw I cannot use currying now, or I will have to add even more fancy code.

 let F1 (a, b) = a + b let F2 = F1 >> (*) 10 F2(2, 3) // returns 50 

Another approach is to use a record. This is a little more straightforward and easier to get at first glance, but requires more code and ceremony. Removes some of the elegance of F #, more like C #.

 type Arg (a, b) = member this.A = a member this.B = b let F1 (a:Arg) = aA + aB let F2 (a:Arg) = F1(a) * 10 F2 (Arg(2, 3)) // returns 50 
+7
source share
3 answers

There is no template for this at all. Using combinators (e.g. curry and uncurry ) as suggested by larsmans is one option, but I think the result is less readable and longer than the explicit version.

If you often use this template, you can define an operator to multiply a function (with two parameters) by a scalar:

 let ( ** ) fx = fun ab -> (fab) * x let F1 xy = x + y let F2 = F1 ** 10 

Unfortunately, you cannot add an implementation of standard numerical operators ( * , etc.) to existing types (for example, 'a -> 'b -> int ). However, this is a fairly frequent request (and that would be useful for other things). Alternatively, you can transfer this function to some object that provides overloaded numerical operators (and contains some Invoke method to run the function).

I think that a suitable name for this would be canceled - you raise the * operator (working on integers) to a version that works with functions that return integers. This is similar to the upgrade that is performed in the C # compiler when you use * to work with types with a null value.

Explain the error message - it complains about the expression F1 * 10 :

error FS0001: Type 'int' does not match type '' a → 'b →' c '

I think this means that the compiler is trying to find an instance for the * operator. On the right side, it turns out that it should be int , so he believes that the left side should also be int , but in fact it is a function of two arguments - something like 'a -> 'b -> c' .

+5
source

That would be pretty smart ...

So smart that he would beat the devil out of the type system. What you want is array programming, as in APL.

Is there a way (almost) to do this?

I am not saying F #, but in Haskell you would not have chosen F1 , and then composed with *10 , then curry:

 f2 = curry ((*10) . uncurry f1) 

What in the dialect of ML, for example F #, becomes something like:

 let curry fxy = f (x,y) let uncurry f (x,y) = fxy let mult xy = x * y let F1 xy = x + y let F2 = curry (uncurry F1 >> mult 10) 

(I was not sure that curry and uncurry are in the F # standard library, so I defined them. There may also be a mult way to partially apply * without defining mult .)

+4
source

BTW, using a point (or rather meaningless in this case) approach, we could define these functions as follows:

 let F1 = (+) let F2 = (<<)((*)10) << F1 
+1
source

All Articles