Scheme - lists and procedure arguments

Started by
7 comments, last by guywithknife 16 years, 2 months ago
Lets say I have a procedure like this:

(define (some-procedure a b c d) (some-code))
and a list like this:

(list 1 2 3)
How could I pass the elements of the list to the parameters expected by the procedure (ie: a -> 1, b -> 2 and c -> 3)? Or even better - a means to produce a new procedure which takes as arguments any arguments of the original procedure which could not be retrieved from the list (eg, if the list contains fewer arguments than the procedure). I hope I'm making sense . All useful responses greatly appreciated.
Advertisement
There's apply, which lets you apply a list of arguments to a function:
(define (func a b c d) ...)(apply func '(1 2 3 4))
However, the list must contain the correct number of arguments (not more, not less), otherwise you will get a runtime error.


Your "even better" sounds a lot like currying, but it's not something Scheme supports AFAIK. You could start faking it:
(define (curry func n-args)  (define (curry-aux acc)    (lambda args      (if (< (+ (length acc) (length args)) n-args)          (curry-aux (append acc args))          (apply func (append acc args)))))  (curry-aux ()))(define cfunc (curry func 4))(func 1 2 3 4) == (cfunc 1 2 3 4) == ((cfunc 1 2) 3 4) == ((((cfunc 1) 2) 3) 4) == ...

apply is compatible with it, so you could apply a partial list of arguments.
(define partially (apply cfunc '(1 2)))(partially 3 4) == (func 1 2 3 4)
Function Currying in Scheme.
Thank you both!

Taking ideas from SamLowry's post and the code for the explicit currying from SiCrane's link, I came up with this, which does exactly what I want it to:
(define (curry fun . args)  (lambda x (apply fun (append args x))))(define (func a b c d)  (display a) (newline)  (display b) (newline)  (display c) (newline)  (display d) (newline))(define cfunc (apply curry (cons func '(1 2))))
> (cfunc 3 4)1234


Rating++ for both of you.

[Edited by - issch on February 12, 2008 1:11:09 PM]
I think that's a little more complicated than necessary :)

(define (curry fun arglst) ; why '.'?  (lambda x (apply fun (append arglst x))))(define (func a b c d)  (begin ; Don't you need this?    (display a) (newline)    (display b) (newline)    (display c) (newline)    (display d) (newline)))(define cfunc (curry func '(1 2))) ; 'apply' is for dealing with things where you; don't know the length ahead of time. When you do, just pass the arguments.
Quote:Original post by Zahlman
I think that's a little more complicated than necessary :)

*** Source Snippet Removed ***


The . makes a difference:
(define (curry1 fun arglst)  (lambda x (apply fun (append arglst x))))(define (curry2 fun . arglst)  (lambda x (apply fun (append arglst x)))); Usage(define curried1 (curry1 func 1 2 3))(define curried2 (curry2 func '(1 2 3)))

I personally prefer the former.

And, begin is not necessary: there is an implicit one in defines and lambdas.
Ah, of course. (Wasn't there another syntax like (define name (lambda x y (stuff)))?)
Quote:Original post by Zahlman
Ah, of course. (Wasn't there another syntax like (define name (lambda x y (stuff)))?)


(define (func a b c)  body)==(define func  (lambda (a b c)     body))


Also, the argument list (in both define and lambda is in some way a pattern, a syntactic shortcut for a "destructuring bind":
...== (define (func . args)  (let ((a (car args))        (b (cadr args))        (c (caddr args)))     body))==(define func  (lambda args    (let ((a (car args))          (b (cadr args))          (c (caddr args)))      body)))
Quote:Original post by Zahlman
I think that's a little more complicated than necessary :)

*** Source Snippet Removed ***

Do'h! You are, of course, correct. If I remove the . I can simplify the code to this:
(define (curry fun args)  (lambda x (apply fun (append args x))))(define (func a b c d)  (display a) (newline)  (display b) (newline)  (display c) (newline)  (display d) (newline))(define cfunc (curry func '(1 2)))

This topic is closed to new replies.

Advertisement