I'm learning about the macro system in Scheme and I thought implementing curried functions would be a good start. This is what I cooked up:
(define-syntax function
(syntax-rules ()
((_ () body ...) (lambda () body ...))
((_ (param) body ...) (lambda (param) body ...))
((_ (param_1 param_2 params ...) body ...) (lambda (param_1 . rest)
(let ((k (function (param_2 params ...) body ...)))
(if (null? rest) k (apply k rest)))))
((_ name params body ...) (define name (function params body ...)))))
This code works as expected to. For example I can define an add
function as follows:
(function add (x y) (+ x y))
Then I can call it normally:
(add 2 3) ; => 5
In addition I can easily partially apply it:
(map (add 10) '(2 3 5 7)) ; => (12 13 15 17)
Now I'm contemplating to allow functions with rest parameters to be curried. So I added a new syntax rule:
((_ (param . params) body ...) (lambda (param . params) body ...))
Unfortunately when I try to create a function using this rule it gives me an error:
(function add (x . y) (apply + `(,x ,@y)))
This is the error message:
Error: invalid syntax in macro form: (x . y)
Call history:
<eval> (##sys#= len7 0)
<eval> (loop11 (##sys#cdr l6) (##sys#+ len7 -1))
<eval> (##sys#cdr l6)
<eval> (##sys#+ len7 -1)
<eval> (##sys#= len7 0)
<eval> (loop11 (##sys#cdr l6) (##sys#+ len7 -1))
<eval> (##sys#cdr l6)
<eval> (##sys#+ len7 -1)
<eval> (##sys#= len7 0)
<eval> (##sys#eq? l6 (quote ()))
<eval> (##sys#car tail15)
<eval> (##sys#cdr tail15)
<eval> (##sys#cons (rename14 (##core#syntax lambda)) (##sys#cons param body))
<eval> (rename14 (##core#syntax lambda))
<eval> (##sys#cons param body)
<syntax> (##core#lambda add (x . y) (apply + (quasiquote ((unquote x) (unquote-splicing y))))) <-
What am I doing wrong?
[The comment is correct; this answer is not currying, it is partial evaluation.]
Just so you know, you don't need to use define-syntax
to support currying. Generally using syntax when you don't need to is frowned upon because 1) syntax introduces different evaluation rules and 2) syntax can't be used as a value.
Here are two implementations, one for (left) curry and one for right curry:
(define (curry func . curry-args)
(lambda args
(apply func (append curry-args args))))
(define (rcurry func . curry-args)
(lambda args
(apply func (append args curry-args))))
Use this as for example:
> (define add-5 (curry + 5))
> (add-5 5)
10