schemeracketcurryingguilechicken-scheme

How to write a self currying lambda macro in scheme?


I would like to write functions like this:

(define foo (\ (a b c) (+ a (+ b c))))

get it automatically transformed into this:

(define foo (lambda (a) (lambda (b) (lambda (c) (+ a (+ b c))))))

and use it like this (if possible):

(map (foo 1 2) (interval 1 10))

as if I was writing this:

(map ((foo 1) 2) (interval 1 10))

I don't know how to write macros in scheme, but I'd need to write a function that transforms a quoted expression

(f arg1 arg2 argn)

like this:

(define-macro clambda ;curried lambda
(lambda xs
 (if (< (length xs) 2)
     (if (eq? 1 (length xs))
         (lambda () xs)
         (lambda (head xs) (tail xs)))
     (lambda (head xs) (clambda (tail xs))))))

How can I do this?


Solution

  • Here is my suggestion for your macro:

    (define-syntax \ 
      (syntax-rules ()
        [(_ "build" (a) body)
         (lambda (a . rest)
           (if (null? rest)
               body
               (error "Too many arguments")))]
        [(_ "build" (a b ...) body)
         (lambda (a . rest)
           (define impl (\ "build" (b ...) body))
           (if (null? rest)
               impl
               (apply impl rest)))]
        [(_ (a b ...) body)
           (\ "build" (a b ...) body)]
        [(_ . rest) (error "Wong use of \\")]))
    
    (define test (\ (a b c) (+ a b c)))
    (define partial (test 4 5))
    (partial 6) ; ==> 15
    

    This does make the resulting code have more overhead since every lambda will apply the next if it gets more arguments. It also will produce an error if you pass too many arguments since you'd otherwise get the unclear "application, not a procedure"

    error you may need to implement.