@krismicinski it’s because I did some moves on that file
yup, my bad..
Anyone mind giving some advice regarding my attempts to add currying to a Scheme interpreter? The idea is that all of these applications should produce the same result: (f a b c d)
((((f a) b) c) d)
(((f a b) c) d)
((f a b c) d)
(((f a) b c) d)
...
After going through a number of half-working versions, this modification to apply seems to work alright (error checking aside): (define (apply* proc actuals)
(if (primop? proc)
(apply proc actuals)
(foldr (lambda (arg f) (let ([body (cadadr f)]
[formals (caadr f)]
[env (caddr f)])
(eval* body
(cons (cons (car formals)
arg)
env))))
proc actuals)))
I’d appreciate some feedback, or just thoughts in general regarding this. It seems fairly trivial (based on resources I came across) to implement this using macros, like a wrapper around all functions that counts arguments and returns either a function of lesser arguments or the result. In fact, it’s easy enough to implement curry as a plain ol’ function. However, as an exercise in aid of getting used to modifying interpreters to try out ideas, I wanted to do it this way. Thanks :slightly_smiling_face:
(I’ve suffixed the “new” versions of eval and apply with *; Racket’s apply is used from applying primitive operations.
@sydney.lambda If it’s truly currying you want (a la our previous discussion), I would do something like this, which essentially desugars multi-argument lambda
/function application into their equivalent single-argument versions.
@sydney.lambda Another way to do it would be to do the desugaring in a separate pass (which I’ve called expand
here), so eval
only has to work with a simplified core language that only has unary lambda
/application.
Thank you so much @lexi.lambda ! Thats a massive help. I especially like the second version; reducing everything down to a simplified base language is something I’m also interested in. Never would have thought to just forgo apply in this case; good to know I’m “allowed” to do that, silly as that may sound! I’ve mostly been using the “Art of the Interpreter” and SICP interpreters as reference and I’ve yet to really find my feet enough to branch away from the main blueprint too much.
I think it’s most helpful to remember that pervasive currying means functions with arity other than 1 do not exist, so “multi-argument” lambda
/application is really just syntactic sugar for nesting.
Therefore, an interpreter for a pervasively curried language only needs to deal with unary functions, since all functions are unary functions.
So only ((((f 1) 2) 3) 4) “really” exists, and all other ways of applying the arguments are just syntactic convenience, if I’m understanding correctly.
Right!
Desugaring is essentially a normalization pass.