A problem with my macro for partial application in Common Lisp

Viewed 140

I am trying to make a macro to achieve partial application in Common Lisp. Here was my thought on how I would implement that in pseudocode:

If my argument list is null, return the function body
Otherwise, cons together "lambda" with the first argument with a recursive call to "partial-lambda" again

(lambda (x y z) (+ x y z) => (lambda (x) (lambda (y) (lambda (z) (+ x y z))))

Here's my code:

(defmacro partial-lambda (params &rest body)
    (if (null params) body
        (lambda ((car params)) (partial-lambda (cdr params) body))))

(partial-lambda (x y z) (+ x y z))

Unfortunately, SBCL gives me this error:

; in: DEFMACRO PARTIAL-LAMBDA
;     (LAMBDA (CAR PARAMS) (PARTIAL-LAMBDA (CDR PARAMS) BODY))
; ==>
;   #'(LAMBDA (CAR PARAMS) (PARTIAL-LAMBDA (CDR PARAMS) BODY))
; 
; caught STYLE-WARNING:
;   The variable CAR is defined but never used.

; file: /Users/caspianahlberg/Desktop/Programming/Lisp/partial_application.lisp
; in: DEFMACRO PARTIAL-LAMBDA
;     (PARTIAL-LAMBDA (CDR PARAMS) BODY)
; 
; caught STYLE-WARNING:
;   undefined function: COMMON-LISP-USER::PARTIAL-LAMBDA
; 
; compilation unit finished
;   Undefined function:
;     PARTIAL-LAMBDA
;   caught 2 STYLE-WARNING conditions
STYLE-WARNING:
   PARTIAL-LAMBDA is being redefined as a macro when it was previously assumed to be a function.

Why does it complain about car never being used? I find that really confusing. Does anyone who is good with CL macros know what I am doing wrong?

2 Answers

Try this:

(defmacro partial-lambda (params &rest body)
    (if (null params) `(progn ,@body)
        `(lambda (,(car params)) (partial-lambda ,(cdr params) ,@body))))

CL-USER 43 > (partial-lambda (x y z) (+ x y z))
#<anonymous interpreted function 40300008DC>

CL-USER 44 > (funcall * 10)
#<anonymous interpreted function 403000094C>

CL-USER 45 > (funcall * 15)
#<anonymous interpreted function 40300009BC>

CL-USER 46 > (funcall * 3)
28

Backquote is variant of QUOTE, which allow unquoting inside it. , is used, when you want unquote something inside quoted section (that expression is replaced with value). And ,@ (unquote-splicing) unquotes something, replaces it and removes parentheses around that value. These operations are commonly used in Lisp macros.

EDIT: (car body) replaced with `(progn ,@body) for handling inputs with more expressions in body: (partial-lambda (x y z) (print 5)(+ x y z)).

A syntax error

(lambda ((car params)) (partial-lambda (cdr params) body))

Common Lisp expects a list of parameters as the second element of a lambda form. A parameter is a symbol. The list of parameters is not evaluated.

Your code has a list (car params) as the first parameter. But Common Lisp expects a symbol.

Your example also does not match the error you have shown.

Probably you did:

(defmacro partial-lambda (params &rest body)
  (if (null params)
      body
      (lambda (car params) (partial-lambda (cdr params) body))))

But then you define a parameter list with the parameters car and params. That makes no sense. That's why th Lisp compiler complains that the variable car is unused.

Macros operate on code

Remember, your macro needs to return code. Code gets created with list operators or a backquote expression.

A backquote expression would look like this (see the answer from Martin Půda):

`(lambda (,(car params)) (partial-lambda ,(cdr params) ,@body))

The backquote allows selected parts of the list template to be evaluated. The comma evaluates and inserts the result. The comma atsign evaluates and splices the result list in.

Related