I'm doing some exercises in Racket, and ran into a problem I couldn't seem to query the docs for.
I want to generate the following curries of
modulo for a list of divisors:
(define multlist '[3 5])
(define modfuncs (map (lambda x ;@ make some modulos
(curry modulo x)) multlist))
This produces a list of curried procedures, which sounds promising, but when I try to test one of them, I get the following error:
-> (car modfuncs)
-> ((car modfuncs) 3)
; modulo: contract violation
; expected: integer?
; given: '(3)
; argument position: 1st
; [,bt for context]
Assuming this isn't a terrible way to do this, how do I unquote the values of
multlist passed to the
map call so these functions will evaluate correctly?
Best How To :
You're actually doing this correctly, albeit with a tiny mistake:
(lambda x (curry modulo x))
This doesn't do what you think it does. What you actually want is this:
(lambda (x) (curry modulo x))
See the difference? In the former,
x is not within an arguments list, so it will actually be passed a list of all arguments passed to the function, not a single argument.
You can see this behavior for yourself with the following simple program:
((lambda x x) 1 2 3)
; => '(1 2 3)
curry function is receiving a list of one number for
x, not an actual integer.
So perhaps the more satisfying answer is: why does Racket do this? Well, this is actually a result of Racket/Scheme's rest parameter syntax. Inserting a dot before the last argument of a lambda makes that parameter a rest parameter, which becomes a list that holds all additional parameters passed to the function.
((lambda (a b . rest) rest) 1 2 3 4 5)
; => '(3 4 5)
However, this isn't actually just a special syntax. The dot notation actually has to do with how Racket's reader reads lists and pairs in syntax. The above parameter list actually becomes an "improper" list made up of the following cons sequence:
(cons 'a (cons 'b 'rest))
The same function without the
rest parameter would have a proper list as its argument declaration, which would look like this instead:
(cons 'a (cons 'b null))
So then, what about the original
x just standing alone? Well, that's an improper list with no preceding arguments! Doing
( . rest) wouldn't make any sense—it would be a syntax error—because you'd be trying to create a pair with no
car element. The equivalent is just dropping the pair syntax entirely.