5

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?

2 Answers 2

2

[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
Sign up to request clarification or add additional context in comments.

1 Comment

This is not creating curried functions; it is creating partially applied functions. With (define (f x y z) (+ x (* y z))) (define g (curry f 1)), ((g 2) 3) should return 7. But you have to call ((curry g 2) 3) for that. Whereas with the OP code, after (function g (x y z) (+ x (* y z))), (g 1 2 3) == ((g 1 2) 3) == (((g 1) 2) 3) == 7.
2

You don't say what version of Scheme you're using. It appears that it doesn't support 'dot' patterns in macros.

In Racket, it looks like your code works:

#lang racket

(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)))))

      ((_ (param . params) body ...) (lambda (param . params) body ...))
      ((_ name params body ...) (define name (function params body ...)))))

(function add (x . y) (apply + `(,x ,@y)))

(add 2 3)

running this produces the answer

5

.

BTW, I think I would have written this as two macros; the dual-purposing of the name 'function' is a bit sketchy... :)

2 Comments

I'm using Chicken Scheme version 4.7.0.
sounds like chicken scheme doesn't support this pattern as written. Perhaps you'd like to give Racket a try? ... :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.