Wishlist Item: Improve curry

Notices and updates
Locked
rickyboy
Posts: 607
Joined: Fri Apr 08, 2005 7:13 pm
Location: Front Royal, Virginia

Wishlist Item: Improve curry

Post by rickyboy »

When I saw recently that Lutz had added curry as a new intrinsic procedure, I thought "way cool!" (I still think that, BTW.)

But apparently, you can't curry a function using more than one (curry) argument:

Code: Select all

> (define (f x y z) (* x (+ y z)))
> (define f-2-3 (curry f 2 3))
> (f-2-3 4)
value expected in function + : z
called from user defined function f
called from user defined function f-2-3
However, you can define, as a macro, your own curry functor which fixes this (you've seen this before, e.g. from John Small):

Code: Select all

(define-macro (currie f)
  (letex ($f (eval f)
          $cargs (map eval (args)))
    (lambda () (apply $f (append (quote $cargs) (args))))))

> (define f-2-3 (curry f 2 3))
> (f-2-3 4)
14
So, I'd like for Lutz to consider changing the intrinsic curry to handle this situation. Then I can get rid of currie! :-)
(λx. x x) (λx. x x)

Jeff
Posts: 604
Joined: Sat Apr 07, 2007 2:23 pm
Location: Ohio
Contact:

Post by Jeff »

I second this.
Jeff
=====
Old programmers don't die. They just parse on...

Artful code

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Post by Lutz »

Originally 'curry' was coded like Rick's currie, but for efficiency reasons I went to the simpler curry for only two functions arguments. The current curry has only the lambda overhead:

Code: Select all

(curry func arg) => (lambda (_x) (func arg _x))
With the current one I wanted a fast currying function for usage primarily in 'find' and 'clean' for binary ops and without the additional overhead of the apply- and append operations necessary in a general curry

Perhaps we should have a second 'curry-nth' which can take more arguments and could additionally have an index parameter telling which parameter of the funtion should be curried?

Lutz

Jeff
Posts: 604
Joined: Sat Apr 07, 2007 2:23 pm
Location: Ohio
Contact:

Post by Jeff »

That sounds good. I just wish there were a useful way to do it recursively, because I really like the sound of "recurry" ;)
Jeff
=====
Old programmers don't die. They just parse on...

Artful code

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

Anyone spare a few moments to explain in simple terms why curry (also known as "Schönfinkelisation" if the Wikipedia is to be believed) is useful? When would I use it?

m i c h a e l
Posts: 394
Joined: Wed Apr 26, 2006 3:37 am
Location: Oregon, USA
Contact:

Post by m i c h a e l »

Hi cormullion!

The following is from the WikiP article you mentioned:
The practical motivation for currying is that very often the functions you get by supplying some but not all of the arguments to a curried function are useful; for example, many languages have a function or operator similar to plus_one. Currying makes it easy to define these functions.
In newLISP:

Code: Select all

> (set '+one (curry + 1))
(lambda (_x) (+ 1 _x))
> (+one 2)
3
> _
Useful? Maybe, but as Lutz said earlier, it's primarily used with the 'find' and 'clean' functions.

m i c h a e l

Jeff
Posts: 604
Joined: Sat Apr 07, 2007 2:23 pm
Location: Ohio
Contact:

Post by Jeff »

It's a fast way of applying a lambda when you know what the first argument should be every on every application. If you wanted to add 10 to every number in '(1 2 3 4 5), you could do:

Code: Select all

(map (lambda (n) (+ n 10)) '(1 2 3 4 5))
Or, you could do:

Code: Select all

(map (curry + 10) '(1 2 3 4 5))
While this doesn't save a lot of time on that small example, when performing more complex applications, curry can save a heck of a lot of time.
Jeff
=====
Old programmers don't die. They just parse on...

Artful code

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

Jeff wrote:It's a fast way of applying a lambda when you know what the first argument should be every on every application.
that's a good way of putting it. I shall steal that phrase for the next iteration of the "introduction to newlisp" (credited of course :-)

The one that sprung to mind immediately was:

Code: Select all

(set 'blank (curry dup " "))
cos I'm often writing this...

cormullion
Posts: 2038
Joined: Tue Nov 29, 2005 8:28 pm
Location: latiitude 50N longitude 3W
Contact:

Post by cormullion »

m i c h a e l wrote:The following is from the WikiP article you mentioned:
I propose that curry be renamed schönfinkelize, though.

Fanda
Posts: 253
Joined: Tue Aug 02, 2005 6:40 am
Contact:

Post by Fanda »

Since many people are used to 'curry' accepting any number of arguments , I would make:

curry - any number of arguments

curry1 - accepting 1 to 4 arguments - special functions for speed optimization
curry2
curry3
curry4

Fanda

rickyboy
Posts: 607
Joined: Fri Apr 08, 2005 7:13 pm
Location: Front Royal, Virginia

Post by rickyboy »

Fanda wrote:Since many people are used to 'curry' accepting any number of arguments , I would make:

curry - any number of arguments

curry1 - accepting 1 to 4 arguments - special functions for speed optimization
curry2
curry3
curry4

Fanda
Good!
(λx. x x) (λx. x x)

Fanda
Posts: 253
Joined: Tue Aug 02, 2005 6:40 am
Contact:

Post by Fanda »

Lutz wrote:Perhaps we should have a second 'curry-nth' which can take more arguments and could additionally have an index parameter telling which parameter of the funtion should be curried?
I like the idea of an index parameter:

Code: Select all

(define (curry-nth n f)
  (letex (n n f f cargs (args))
    (lambda () (apply f (append (0 n (args)) 'cargs (n (args)))))))

Code: Select all

(define f (curry-nth 1 explode 2))
(f "newLISP") => ("ne" "wL" "IS" "P")

(define f (curry-nth 1 explode 2 true))
(f "newLISP") => ("ne" "wL" "IS")

(define f (curry-nth 0 explode "apple"))
(f 2) => ("ap" "pl" "e")
(f 2 true) => ("ap" "pl")

(define f (curry-nth 1 append '(x y)))
(f '(a)) => (a x y)
(f '(a b)) => (a b x y)
(f '(a b) '(c d)) => (a b x y c d)
Fanda

Locked