I'm trying to understand how clojure macros apply to lists. I'm confused by the following:
(defmacro islist [f] (list? f))
(islist (1 2)) ; true
(islist '(1 2)) ; false
(islist (quote (1 2))) ; true
Is this expected? I've noticed that lists I pass to to macros return false when evaluated with list? inside the macro. That is, the second example is particularly confusing.
Within the macro '(1 2) is of type clojure.lang.Cons (you can check this by changing list? to type). list? returns true iff the operand is of type clojure.lang.IPersistentList.
user=> (isa? clojure.lang.Cons clojure.lang.IPersistentList)
false
The reason clojure.lang.Cons appears is because the reader constructs a cons cell when expanding '(1 2) to (quote (1 2)), whereas it doesn't when you spell out quote directly as (quote (1 2)).
You probably want to use seq? instead of list?.
Related
I would like to known how deterministic Racket's evaluation order is when set! is employed. More specifically,
Does #%app always evaluates its arguments from left to right?
If no, can the evaluation of different arguments be intertwined?
Take, for instance, this snippet:
#lang racket
(define a 0)
(define (++a) (set! a (add1 a)) a)
(list (++a) (++a)) ; => ?
Could the last expression evaluate to something different than '(1 2), such as '(1 1), '(2 2) or '(2 1)?
I failed to find a definite answer on http://docs.racket-lang.org/reference.
Unlike Scheme, Racket is guaranteed left to right. So for the example call:
(proc-expr arg-expr ...)
You can read the following in the Guide: (emphasis mine)
A function call is evaluated by first evaluating the proc-expr and all
arg-exprs in order (left to right).
That means that this program:
(define a 0)
(define (++a) (set! a (add1 a)) a)
(list (++a) (++a))
; ==> (1 2)
And it is consistent. For Scheme (2 1) is an alternative solution. You can force order by using bindings and can ensure the same result like this:
(let ((a1 (++ a)))
(list a1 (++ a)))
; ==> (1 2)
How does lisp quote work internally?
For example:
(quote (+ 1 (* 1 2)) )
seems to be equivalent to
(list '+ 1 (list '* 1 2))
which means it is some how symbolizing the Head values recursively. Is this function a built in?
Run (equal (quote (+ 1 (* 1 2))) (list '+ 1 (list '* 1 2))) if you don't believe me.
How does it work?
quote is really really simple to implement. It does mostly nothing. The quote special operator just returns the enclosed object like it is. Nothing more. No evaluation. The object is not changed in any way.
Evaluation of quoted forms
Probably a good time to read McCarthy, from 1960:
Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I
Pages 16/17 explain evaluation with eval. Here:
eq [car [e]; QUOTE] → cadr [e];
or in s-expression notation:
(cond
...
((eq (car e) 'quote)
(cadr e))
...)
Above code implements the evaluation rule for QUOTE: If the expression is a list and the first element of the list is the symbol QUOTE, then return the second element of the list.
Equivalence of a quoted list with a list created by LIST
(equal (quote (+ 1 (* 1 2)))
(list '+ 1 (list '* 1 2)))
The result is T. This means that both result lists are structurally equivalent.
(eq (quote (+ 1 (* 1 2)))
(list '+ 1 (list '* 1 2)))
The result is NIL. This means that the first cons cell of the linked lists are not the same objects. EQ tests whether we really have the same cons cell object.
QUOTE returns a literal data object. The consequences of modifying this object is undefined. So, don't do it.
LIST returns a new freshly consed list each time it is called. The fresh new list will not share any cons cells with any earlier allocated list.
So the main difference is that QUOTE is a built-in operator, which returns literal and unevaluated data. Whereas LIST is a function which creates a new,fresh list with its arguments as contents.
See the effects with respect to EQ and EQUAL:
CL-USER 6 >
(flet ((foo () (quote (+ 1 (* 1 2))))
(bar () (list '+ 1 (list '* 1 2))))
(list (list :eq-foo-foo (eq (foo) (foo)))
(list :eq-foo-bar (eq (foo) (bar)))
(list :eq-bar-bar (eq (foo) (bar)))
(list :equal-foo-foo (equal (foo) (foo)))
(list :equal-foo-bar (equal (foo) (bar)))
(list :equal-bar-bar (equal (foo) (bar)))))
((:EQ-FOO-FOO T)
(:EQ-FOO-BAR NIL)
(:EQ-BAR-BAR NIL)
(:EQUAL-FOO-FOO T)
(:EQUAL-FOO-BAR T)
(:EQUAL-BAR-BAR T))
is quote a function?
quote can't be a function, since it returns its enclosed data unevaluated. Thus it is a special evaluation rule.
If quote were a function, it's arguments were evaluated. But that's exactly what is NOT what quote is supposed to do.
why does Lisp need QUOTE?
Lisp usually uses s-expressions to write Lisp code. So s-expressions have a both purpose to denote data and we use it to write programs. In a Lisp program lists are used for function calls, macro forms and special forms. symbols are used as variables:
(+ n 42)
Here (+ n 42) is a list and n is a symbol. But we also want to use lists as data in our programs and we want to use symbols as data. Thus we have to quote them, so that Lisp will not see them as programs, but as data:
(append '(+ n) '(42)) evaluates to (+ n 42)
Thus in a Lisp program, lists and variables are by default part of the language elements, for example as function calls and variables. If we want to use lists and symbols as literal data, we have to quote them, to prevent the evaluator treating them as Lisp code to evaluate.
quote does nothing more than return its argument unevaluated. But what is an unevaluated argument?
When a Lisp program is defined, it is either read from textual source into s-expression form or constructed directly in terms of s-expressions. A macro would be an example of generating s-expressions. Either way there is a data structure comprising (mostly) symbols and conses that represents the program.
Most Lisp expressions will call upon evaluation and compilation machinery to interpret this data structure as terms in a program. quote is treated specially and passed these uninterpreted symbols and conses as its argument. In short, quote does almost nothing - the value it returns already exists and is simply passed through.
You can observe the difference between passing through and fresh construction by using eq to test the identity of the return value of quote:
(defun f () '(1 2))
(defun g () (list 1 2))
(eq (f) (f)) => T
(eq (g) (g)) => NIL
As you can see, quote returns the same conses each time through.
I have this macro (from the clojure-koans) that should allow the use of infix operators:
(defmacro infix-better [form]
`(~(second form)
(first form)
(last form) ))
It does what it is supposed to, but doesn't exactly expand to the same expression. For example:
user=> (= '(* 10 2) (macroexpand '(infix-better (10 * 2))))
false
user=> '(* 10 2)
(* 10 2)
user=> (macroexpand '(infix-better (10 * 2)))
(* (clojure.core/first user/form) (clojure.core/last user/form))
The last output would end up being (* 10 2) when the inner expressions are evaluated but the equality test returns false since (clojure.core/first user/form), strictly speaking, isn't 10.
How can I have the expanded macro equal the equivalent hard-coded Clojure?
You have to unquote the second and third forms, just like you did the first, with ~ - "The last output would end up being (* 10 2) when the inner expressions are evaluated" is not in any way true - the inner expressions have already passed their chance to be evaluated.
(defmacro infix-better [form]
`(~(second form)
~(first form)
~(last form)))
Would fix it and keep your code structured the same, but really destructuring gives you a much nicer result:
(defmacro infix-better [[x op y]]
(list op x y)) ;; or `(~op ~x ~y)
Does someone know why the following produces the expected result - (2 4 6)
(defmacro mult2 (lst)
(define (itter x)
(list '* 2 x))
`(list ,#(map itter lst)))
(mult2 (1 2 3))
while I expected that this one would (with the list identifier)
(defmacro mult2 (lst)
(define (itter x)
(list '* 2 x))
`(list ,#(map itter lst)))
(mult2 '(1 2 3))
Macro "arguments" are not evaluated. So, when you pass in '(1 2 3), i.e., (quote (1 2 3)), that is exactly what the macro sees.
P.S. You are much better off using hygienic macros in Scheme. Here's an example using syntax-case:
(define-syntax mult2
(lambda (stx)
(define (double x)
#`(* 2 #,x))
(syntax-case stx ()
((_ lst)
#`(list #,#(map double (syntax-e #'lst)))))))
(That's still not how such a macro is idiomatically written, but I tried to mirror your version as closely as possible.)
That's because the '(1 2 3) is expanded by the reader into (quote (1 2 3)). Since you only destructure one list in your macro, it won't work as expected.
Some general advice: if you're working in Racket you probably want to avoid using defmacro. That is definitely not the idiomatic way to write macros. Take a look at syntax-rules and, if you want to define more complicated macros, syntax-parse. Eli also wrote an article explaining syntax-case for people used to defmacro.
I am having trouble with Lisp's backquote read macro. Whenever I try to write a macro that seems to require the use of embedded backquotes (e.g., ``(w ,x ,,y) from Paul Graham's ANSI Common Lisp, page 399), I cannot figure out how to write my code in a way that compiles. Typically, my code receives a whole chain of errors preceded with "Comma not inside a backquote." Can someone provide some guidelines for how I can write code that will evaluate properly?
As an example, I currently need a macro which takes a form that describes a rule in the form of '(function-name column-index value) and generates a predicate lambda body to determine whether the element indexed by column-index for a particular row satisfies the rule. If I called this macro with the rule '(< 1 2), I would want a lambda body that looks like the following to be generated:
(lambda (row)
(< (svref row 1) 2))
The best stab I can make at this is as follows:
(defmacro row-satisfies-rule (rule)
(let ((x (gensym)))
`(let ((,x ,rule))
(lambda (row)
(`,(car ,x) (svref row `,(cadr ,x)) `,(caddr ,x))))))
Upon evaluation, SBCL spews the following error report:
; in: ROW-SATISFIES-RULE '(< 1 2)
; ((CAR #:G1121) (SVREF ROW (CADR #:G1121)) (CADDR #:G1121))
;
; caught ERROR:
; illegal function call
; (LAMBDA (ROW) ((CAR #:G1121) (SVREF ROW (CADR #:G1121)) (CADDR #:G1121)))
; ==>
; #'(LAMBDA (ROW) ((CAR #:G1121) (SVREF ROW (CADR #:G1121)) (CADDR #:G1121)))
;
; caught STYLE-WARNING:
; The variable ROW is defined but never used.
; (LET ((#:G1121 '(< 1 2)))
; (LAMBDA (ROW) ((CAR #:G1121) (SVREF ROW (CADR #:G1121)) (CADDR #:G1121))))
;
; caught STYLE-WARNING:
; The variable #:G1121 is defined but never used.
;
; compilation unit finished
; caught 1 ERROR condition
; caught 2 STYLE-WARNING conditions
#<FUNCTION (LAMBDA (ROW)) {2497F245}>
How can I write macros to generate the code I need, and in particular, how do I implement row-satisfies-rule?
Using the ideas from Ivijay and discipulus, I have modified the macro so that it compiles and works, even allowing forms to be passed as the arguments. It runs a bit differently from my originally planned macro since I determined that including row as an argument made for smoother code. However, it is ugly as sin. Does anyone know how to clean it up so it performs the same without the call to eval?
(defmacro row-satisfies-rule-p (row rule)
(let ((x (gensym))
(y (gensym)))
`(let ((,x ,row)
(,y ,rule))
(destructuring-bind (a b c) ,y
(eval `(,a (svref ,,x ,b) ,c))))))
Also, an explanation of clean, Lispy ways to get macros to generate code to properly evaluate the arguments at runtime would be greatly appreciated.
First of all, Lisp macros have "destructuring" argument lists. This is a nice feature that means instead of having an argument list (rule) and then taking it apart with (car rule) (cadr rule) (caddr rule), you can simply make the argument list ((function-name column-index value)). That way the macro expects a list of three elements as an argument, and each element of the list is then bound to the corresponding symbol in the arguemnt list. You can use this or not, but it's usually more convenient.
Next, `, doesn't actually do anything, because the backquote tells Lisp not to evaluate the following expression and the comma tells it to evaluate it after all. I think you meant just ,(car x), which evaluates (car x). This isn't a problem anyway if you use destructuring arguments.
And since you're not introducing any new variables in the macro expansion, I don't think (gensym) is necessary in this case.
So we can rewrite the macro like this:
(defmacro row-satisfies-rule ((function-name column-index value))
`(lambda (row)
(,function-name (svref row ,column-index) ,value)))
Which expands just how you wanted:
(macroexpand-1 '(row-satisfies-rule (< 1 2)))
=> (LAMBDA (ROW) (< (SVREF ROW 1) 2))
Hope this helps!
If you need the argument to be evaluated to get the rule set, then here's a nice way to do it:
(defmacro row-satisfies-rule (rule)
(destructuring-bind (function-name column-index value) (eval rule)
`(lambda (row)
(,function-name (svref row ,column-index) ,value))))
Here's an example:
(let ((rules '((< 1 2) (> 3 4))))
(macroexpand-1 '(row-satisfies-rule (car rules))))
=> (LAMBDA (ROW) (< (SVREF ROW 1) 2))
just like before.
If you want to include row in the macro and have it give you your answer straightaway instead of making a function to do that, try this:
(defmacro row-satisfies-rule-p (row rule)
(destructuring-bind (function-name column-index value) rule
`(,function-name (svref ,row ,column-index) ,value)))
Or if you need to evaluate the rule argument (e.g. passing '(< 1 2) or (car rules) instead of (< 1 2)) then just use (destructuring-bind (function-name column-index value) (eval rule)
Actually, a function seems more appropriate than a macro for what you're trying to do. Simply
(defun row-satisfies-rule-p (row rule)
(destructuring-bind (function-name column-index value) rule
(funcall function-name (svref row column-index) value)))
works the same way as the macro and is much neater, without all the backquoting mess to worry about.
In general, it's bad Lisp style to use macros for things that can be accomplished by functions.
One thing to understand is that the backquote feature is completely unrelated to macros. It can be used for list creation. Since source code usually consists of lists, it may be handy in macros.
CL-USER 4 > `((+ 1 2) ,(+ 2 3))
((+ 1 2) 5)
The backquote introduces a quoted list. The comma does the unquote: the expression after the comma is evaluated and the result inserted. The comma belongs to the backquote: the comma is only valid inside a backquote expression.
Note also that this is strictly a feature of the Lisp reader.
Above is basically similar to:
CL-USER 5 > (list '(+ 1 2) (+ 2 3))
((+ 1 2) 5)
This creates a new list with the first expression (not evaluated, because quoted) and the result of the second expression.
Why does Lisp provide backquote notation?
Because it provides a simple template mechanism when one wants to create lists where most of the elements are not evaluated, but a few are. Additionally the backquoted list looks similar to the result list.
you don't need nested backquotes to solve this problem. Also, when it's a macro, you don't have to quote your arguments. So (row-satisfies-rule (< 1 2)) is lispier than (row-satisfies-rule '(< 1 2)).
(defmacro row-satisfies-rule (rule)
(destructuring-bind (function-name column-index value) rule
`(lambda (row)
(,function-name (svref row ,column-index) ,value))))
will solve the problem for all calls in the first form. Solving the problem when in the second form is left as an exercise.