Talk:Partial function application: Difference between revisions

From Rosetta Code
Content added Content deleted
Line 234: Line 234:
</lang>
</lang>


Not entirely-correct Ruby 1.9 implementation:
Possible-correct Ruby 1.9 implementation:


<lang ruby>
<lang ruby>
Line 250: Line 250:


u = f2.curry[7][9]
u = f2.curry[7][9]
w = g.call(7).call(9)
v = f2.curry[7,9]
w = g[7][9]
puts [ [1,2,3,4,5].map {|x| u[x]} \
puts [ [1,2,3,4,5].map {|x| u[x]} \
, [1,2,3,4,5].map {|x| w.call x} ]
, [1,2,3,4,5].map {|x| v[x]} \
, [1,2,3,4,5].map {|x| w[x]} ]
</lang>
</lang>

Revision as of 16:12, 15 April 2011

Explicit curry vs Partial application

In Python there is a clear difference. Here's explicit currying:

<lang python>def fsf1(fs, f1):

   return lambda s: fs(f1, s)</lang>

I would like to tie this task down, but now recognise that it may be difficult.

Any programmers, especially those with functional as well as none functional language experience care to comment? --Paddy3118 02:28, 26 March 2011 (UTC)

With Common Lisp, the explicit currying seems to be the only way to do the partial application. I try to show this with code. This is mapcar with 2 arguments.
<lang lisp>CL-USER> (defun f1 (n) (* n 2))

F1 CL-USER> (mapcar #'f1 '(2 3 5 7)) (4 6 10 14)</lang>

I can use lambda for the explicit currying, like one would in Python.
<lang lisp>CL-USER> ((lambda (s) (mapcar #'f1 s)) '(2 3 5 7))

(4 6 10 14)</lang>

I can also define a partial function for the partial application; but it uses the explicit currying to do so.
<lang lisp>CL-USER> (defun partial (f &rest args)

(lambda (&rest args2) (apply f (append args args2)))) PARTIAL CL-USER> (funcall (partial #'mapcar #'f1) '(2 3 5 7)) (4 6 10 14)</lang>

There is not much reason to write (partial #'mapcar #'f1) instead of (lambda (s) (mapcar #'f1 s)). This would be like writing sum((2, 3)) instead of 2 + 3 in Python. --Kernigh 02:34, 1 April 2011 (UTC)
Is it the case that there is no real distinction in Lisp, but a significant distinction in other languages?
What about the other feature I seem to see in partial application: that of not needing to refer explicitely to the other arguments of the function being partially applied? E.g. with function f(a,b,c,d); you can partial(f, a=value1) to produce f'(b,c,d) without mention of b, c, and d when calling partial. --Paddy3118 06:29, 1 April 2011 (UTC)
First considering the feature of not referring to other arguments, I would expect this to be possible in most languages with dynamic types, but not possible in languages with static type checking. Kernigh's partial handles this just fine using apply, for example. This document I found calls it generalized explicit currying and gives example code in Scheme. In Go, with it's static type checking, I can write a partial that does explicit currying for functions with specific type signatures, but I can't write a partial that does generalized explicit currying for functions with arbitrary type signatures.
Which leads back to the first question of the distinction between (partial #'mapcar #'f1) and (lambda (s) (mapcar #'f1 s)). There are two distinctions! Function/lambda expression and generalized/specific. (And they are orthogonal: You could write a specific function or a generalized lambda expression.) Anyway, there seems little point in either a function or generality in the case of this task as currently written. You could just write fsf1 = lambda s: fs(f1, s) in Python, for example.
As far as changes to the task, I think it's fine the way it is. —Sonia 06:28, 13 April 2011 (UTC)
Hi. Ocaml and Haskell are statically typed and yet don't seem to need to mention the other arguments. At this stage, I want a task that fits the page title so am trying to explore what partial function application could mean for many languages. --Paddy3118 07:00, 13 April 2011 (UTC)
If not mentioning the other args. was made a task restriction, could it then be done in Go? --Paddy3118 07:04, 13 April 2011 (UTC)
Touché. If not mentioning the other args was made a task restriction, I'm pretty sure it could not be done in Go. Go requires static typing yet has no way of specifying one function type in terms of another function type. It might be a good restriction. Simple closures are already demonstrated in tasks like Function composition and First class functions. I might reword it "Note that in the partial application of a parameter, (in the above case param1), the only inputs are f and param1. The return value and arguments of f' are determined solely by f and are not explicitly mentioned. This is an essential feature of partial function application." I might also remove "( s )" from task bullets 4 and 5, so that they read just "Partially apply f1 to fs to form function fsf1." It's a little more cryptic, but it removes a possible suggestion that it's okay to specify the argument list of fsf1. —Sonia 18:32, 13 April 2011 (UTC)
Thanks Sonia. Anyone else OK with such an update? (Remember, the idea isn't to exclude Go; it is to more explicitely define partial application). --Paddy3118 21:08, 13 April 2011 (UTC)
The update is OK with me.
I used (partial #'fs #'f1) to solve Common Lisp. I also solved Java. Java is a statically typed language, so the solution is like Ocaml or Haskell: I have to curry the fs() method. I start with this Java code.
<lang java>static int[] fs(IntegerFunction f, int[] s) {

int[] r = new int[s.length]; for (int i = 0; i < s.length; i++) r[i] = f.call(s[i]); return r; }

static int[] fsf1(int[] s) { return fs(f1, s); }</lang>

This fsf1() explicitly curries fs(), mentions s and passes the return value from fs(). I change the code.
<lang java>interface SequenceFunction {

int[] call(int[] arg); }

static SequenceFunction fs(final IntegerFunction f) { return new SequenceFunction() { public int[] call(int[] s) { int[] r = new int[s.length]; for (int i = 0; i < s.length; i++) r[i] = f.call(s[i]); return r; } }; }

static SequenceFunction fsf1 = fs(f1);</lang>

This fs() explicitly curries itself. So fsf1 never has to mention s nor pass the return value from fs(). --Kernigh 20:26, 14 April 2011 (UTC)
Hi Kernigh, the above is not like Haskel, in fact it doesn't really answer the task as you have made fs a function of only f, then called it with different f. Partial application would be like the Haskel: fs is a function of f and s and then fsfl is the result of applying only f1 to fs, without mention of any other argument. The above may give a result, but it is how it gets to that result that is the issue. --Paddy3118 23:07, 14 April 2011 (UTC)
I believed the description of the Haskell solution: "All functions actually take exactly one argument." I tried to do the same thing for Java: I wrote an fs() method that takes exactly one argument. The Java syntax is far worse than the Haskell syntax, but the result seems to be the same: fs takes exactly one parameter f and returns another function that takes exactly one parameter s. When one says fs(arg1).call(arg2) in Java, then fs is a function of two parameters.
One problem is that some program might already have fs(arg1, arg2), and I want to partially apply it. I might solve this by wrapping the method so I have both fs(arg1, arg2) and fs_curried(arg1).call(arg2). It might look like this.
<lang java>static int[] fs(IntegerFunction f, int[] s) {

int[] r = new int[s.length]; for (int i = 0; i < s.length; i++) r[i] = f.call(s[i]); return r; }

interface SequenceFunction { int[] call(int[] arg); }

static SequenceFunction fsCurried(final IntegerFunction f) { return new SequenceFunction() { public int[] call(int[] s) { return fs(f, s); } }; }

static SequenceFunction fsf1 = fsCurried(f1);</lang>

With the current solution for Java, fs(arg1).call(arg2) is already a function of two arguments, and there is no reason to also have fs(arg1, arg2).
Haskell seems to have an analogy for fs(arg1, arg2). I looked around the Haskell 2010 report, and learned that Haskell has tuples. A function has only one parameter, but that parameter might be a tuple of 2 items. I also found these functions in the Haskell prelude:
<lang haskell>-- curry converts an uncurried function to a curried function;

-- uncurry converts a curried function to a function on pairs. curry  :: ((a, b) -> c) -> a -> b -> c curry f x y = f (x, y)

uncurry  :: (a -> b -> c) -> ((a, b) -> c) uncurry f p = f (fst p) (snd p)</lang>

It seems that one might define fs (f, s) = map f s, a function that takes a tuple and returns a sequence, then use curry fs f1 as partial application. (There is no Haskell implementation on my computer, so I cannot test this. Perhaps I am wrong.) With the current solution for Haskell, fs arg1 arg2 is already a function of two arguments, and there is no reason to also have fs (arg1, arg2).
The current Java solution already solves the task: fs(arg1).call(arg2) is a function of two arguments, and fs(arg1) is a partial application. --Kernigh 02:15, 15 April 2011 (UTC)

Is Scala correct?

I don't know scala, but it seems that in the following: <lang scala>def fs(f:Int=>Int, s:List[Int])=s map f def f1(x:Int)=x*2 def f2(x:Int)=x*x

def fsf1=fs(f1,_:List[Int]) def fsf2=fs(f2,_:List[Int])

println(fsf1(List(0,1,2,3))) println(fsf1(List(2,4,6,8))) println(fsf2(List(0,1,2,3))) println(fsf2(List(2,4,6,8)))</lang> In the definition of fsf1, the second argument to fs is explicitely mentioned as '_' - as is the return type of List[Int]. Compare it to the Haskel where both are implied.

I think I will have to mark this as incorrect. --Paddy3118 23:45, 14 April 2011 (UTC)

Is Lisp correct?

I need to query the fact that partial only applies in this case of a being applied to a function of two arguments. A correct partial should, given a function with N parameters and any of M arguments, where M<Nm should then return a partially applied function of N-M parameters. I.e. it should work equally well for fs2(fa, fb, s) where partial(fs2, f1) should return a function of (fb, s); and partial(fs2, f1, f2) should return a function of s.

Lisp may well have a way of doing this, but I don't think the present example shows it. --Paddy3118 23:57, 14 April 2011 (UTC)

The current task only requires N = 2. The current partial uses &rest to accept a variable number of arguments. It can work when N > 2, but I never tested it until now. The next example shows N = 6 and N = 4.
<lang lisp>CL-USER> (defun partial (func &rest args1)

(lambda (&rest args2) (apply func (append args1 args2)))) PARTIAL CL-USER> (defun take6 (a b c d e f) (list f b d c a e)) TAKE6 CL-USER> (take6 11 22 33 44 55 66) (66 22 44 33 11 55) CL-USER> (defvar take2 (partial #'take6 11 22 33 44)) TAKE2 CL-USER> (funcall take2 55 66) (66 22 44 33 11 55)</lang>

--Kernigh 00:53, 15 April 2011 (UTC)
Not only does &rest do the right thing with the arguments, but apply does the right thing with the return value. I think this lisp solution satisfies the concept of partial function evaluation. —Sonia 01:45, 15 April 2011 (UTC)

Is D correct?

The D solution is a not perfect implementation, it's an approximation, but it's a D idiomatic way to solve the problem. If you don't accept an approximation, it becomes hard to implement in D. My suggestion is to accept approximate solutions too.

And in the D version fs() is a templated function. It's the way you write generic code in such languages.

Proposal for new task description

I would propose to extend the task description here include both currying and partial application:

  • Define the linear function f : (a, b, x) ↦ ax + b in uncurried form.
  • Define the linear function g : (a, b, x) ↦ ax + b in curried form.
  • Perform the following operations:
    1. Curry f, apply a = 7, b = 9, apply to a sequence of x's.
    2. Partially apply a = 7 and b = 9 to f, and apply to a sequence of x's.
    3. Apply a = 7 and b = 9 to g, and apply to a sequence of x's.

Ruud 15:32, 15 April 2011 (UTC)


Here are samples in Haskell and Python:

<lang haskell> module Main where

curry3 :: ((a, b, c) -> r) -> a -> b -> c -> r curry3 f x y z = f (x, y, z)

papply2 :: ((a, b) -> r) -> a -> b -> r papply2 f x = \y -> f (x, y)

papply3 :: ((a, b, c) -> r) -> a -> (b, c) -> r papply3 f x = \(y, z) -> f (x, y, z)

f :: (Integer, Integer, Integer) -> Integer f (a, b, x) = a * x + b

g :: Integer -> Integer -> Integer -> Integer -- idiomatic g a b x = a * x + b

g' :: Integer -> (Integer -> (Integer -> Integer)) g' = \a -> \b -> \x -> a * x + b

main = let u = curry3 f

          v = papply2 (papply3 f 7) 9
          w = g 7 9    -- idiomatic
      in print [map (u 7 9) [1..5], map v [1..5], map w [1..5]]

</lang>

<lang python> from functools import partial

def curry3(f):

 return lambda a: lambda b: lambda x: f(a, b, x)

def f(a, b, x): # idiomatic

 return a * x + b

def g(a):

 return lambda b: lambda x: a * x + b

def main():

 u = curry3(f)
 v = partial(f, 7, 9)
 w = g(7)(9)    # non-idiomatic
 print [map(u(7)(9), [1,2,3,4,5]), map(v, [1,2,3,4,5]), map(w, [1,2,3,4,5])]

</lang>

Possible-correct Ruby 1.9 implementation:

<lang ruby> def f(a, b, x)

 a * x + b

end

def f2

 lambda {|a, b, x| a * x + b}

end

def g

 proc { |a| proc { |b| proc { |x| a * x + b } } }

end

u = f2.curry[7][9] v = f2.curry[7,9] w = g[7][9] puts [ [1,2,3,4,5].map {|x| u[x]} \

    , [1,2,3,4,5].map {|x| v[x]} \
    , [1,2,3,4,5].map {|x| w[x]} ]

</lang>