Conditional variable binding in Common Lisp - lisp

I want to execute a function with 2 local variables, but the values of these of these variables should depend on some condition. For example, let's say I have 2 variables x and y, and I want to swap them inside let if y > x. The swap should be temporary, I don't want to mutate state with rotatef. My code would look something like:
(setq x 2)
(setq y 1)
(let (if (> x y) ((x y) (y x)) ((x x) (y y)))
(cons x y)) ; should return (1 . 2)
But the expression inside let is not valid Lisp. How do I conditionally assign values to local variables? The work around is to put the body in flet and call it with different arguments, but it look clumsy:
(flet ((body (x y) (cons x y)))
(if (< x y)
(body x y)
(body y x)))

Multiple-value-bind and values
There are lots of alternatives, some of which have already been pointed out in other answers. I think that the question in the title ("Conditional variable binding in Common Lisp") is a nice case for multiple-value-bind and values. I've used different variable names in the following just to make it clear where x and y are, and where the original values are coming from. The names can be the same, though; this just shadows them inside.
(let ((a 3)
(b 2))
(multiple-value-bind (x y)
(if (< a b)
(values a b)
(values b a))
(cons x y)))
;=> (2 . 3)
Then, using a bit of macrology, we can make this a bit cleaner, much like coredump did:
(defmacro if-let (test bindings &body body)
"* Syntax:
let ({var | (var [then-form [else-form]])}*) declaration* form* => result*
* Description:
Similar to LET, but each binding instead of an init-form can have a
then-form and and else-form. Both are optional, and default to NIL.
The test is evaluated, then variables are bound to the results of the
then-forms or the else-forms, as by LET."
(let ((bindings (mapcar #'(lambda (binding)
(destructuring-bind (variable &optional then else)
(if (listp binding) binding (list binding))
(list variable then else)))
bindings)))
`(multiple-value-bind ,(mapcar 'first bindings)
(if ,test
(values ,#(mapcar 'second bindings))
(values ,#(mapcar 'third bindings)))
,#body)))
(pprint (macroexpand-1 '(if-let (< x y) ((x x y)
(y y x))
(cons x y))))
; (MULTIPLE-VALUE-BIND (X Y)
; (IF (< X Y)
; (VALUES X Y)
; (VALUES Y X))
; (CONS X Y))
(let ((a 3) (b 2))
(if-let (< a b)
((x a b)
(y b a))
(cons x y)))
;=> (2 . 3)
Comparison with progv
In terms of use, this has some similarities with sindikat's answer, but multiple-value-bind establishes bindings just like let does: lexical by default, but a global or local special declaration will make the bindings dynamic. On the other hand, progv establishes dynamic bindings. This means that if the bindings are entirely introduced by progv, you won't see much difference (except in trying to return closures), but that you can't shadow bindings. We can see this without having to do any conditional work at all. Here are two sample snippets. In the first, we see that the inner reference to x actually refers to the lexical binding, not the dynamic one established by progv. To refer to the one established by progv, you actually need to declare the inner reference to be special. progv doesn't accept declarations, but we can use locally.
(let ((x 1))
(progv '(x) '(2)
x))
;=> 1
(let ((x 1))
(progv '(x) '(2)
(locally (declare (special x))
x)))
;=> 2
multiple-value-bind actually does the binding the way we'd expect:
(let ((x 1))
(multiple-value-bind (x) (values 2)
x))
;=> 2
It's probably better to use a binding construct like multiple-value-bind that establishes lexical bindings by default, just like let does.

If you don't want to use progv, as mentioned by sindikat, you always can wtite something like that:
(defmacro let-if (if-condition then-bindings else-bindings &body body)
`(if ,if-condition
(let ,then-bindings
,#body)
(let ,else-bindings
,#body)))
So expression like
(let-if (> x y) ((x y) (y x)) ((x x) (y y))
(cons x y))
Will expand into:
(IF (> X Y)
(LET ((X Y) (Y X))
(CONS X Y))
(LET ((X X) (Y Y))
(CONS X Y)))

rotatef
How about:
CL-USER> (defvar x 2)
X
CL-USER> (defvar y 1)
Y
CL-USER> (let ((x x) ; these variables shadow previously defined
(y y)) ; X and Y in body of LET
(when (> x y)
(rotatef x y))
(cons x y))
(1 . 2)
CL-USER> x ; here the original variables are intact
2 ; ^
CL-USER> y ; ^
1 ; ^
However, I think that in every such practical case there are lispier ways to solve problem without macros. Answer by msandiford is probably the best from functional point of view.
psetf
Although rotatef is really efficient method (it probably would be compiled to about three machine instructions swapping pointers in memory), it is not general.
Rainer Joswing posted just a great solution as a comment shortly after posting of the question. To my shame, I checked macro psetf only few minutes ago, and this should be very efficient and general solution.
Macro psetf first evaluates its even arguments, then assigns evaluated values to variables at odd positions just like setf does.
So we can write:
(let ((x x)
(y y))
(when (> x y)
(psetf x y y x))
...)
And that's it, one can conditionally rebind anything to anything. I think it's way better than using macros. Because:
I don't think it's such a common situation;
Some macros in the posted answers repeat their body code, which may be really big: thus you get bigger compiled file (it's fair price for using macro, but not in this case);
Every custom macro does make code harder to understand for other people.

One solution is to use progv instead of let, its first argument is a list of symbols to bind values to, second argument is a list of values, rest is body.
(progv '(x y) (if (< x y) (list x y) (list y x))
(cons x y)) ; outputs (1 . 2)

Another alternative might be:
(let ((x (min x y))
(y (max x y)))
(cons x y))

My suggestion would be one of destructuring-bind or multiple-value-bind.
If you anticipate needing to do this a lot, I would suggest using a macro to generate the bindings. I've provided a possible macro (untested).
(defmacro cond-let (test-expr var-bindings &body body)
"Execute BODY with the VAR-BINDINGS in place, with the bound values depending on
the trueness of TEST-EXPR.
VAR-BINDINGS is a list of (<var> <true-value> <false-value>) with missing values
being replaced by NIL."
(let ((var-list (mapcar #'car var-bindings))
(then-values (mapcar #'(lambda (l)
(when (cdr l)
(nth 1 l)))
var-bindings))
(else-values (mapcar #'(lambda (l)
(when (cddr l))
(nth 2 l)))
var-bindings))
`(destructuring-bind ,var-list
(if ,test-expr
(list ,#then-values)
(list ,#else-values)))))

Related

What is a didatic example of the with-slots macro in CLOS?

The Common Lisp HyperSpec covers the with-slots macro. However, the example is hard to grasp.
Is there an easier and more didactic example about it?
To better understand with-slots, one should look into defclass first.
No reader or writer functions are defined by default; their generation must be explicitly requested. However, slots can always be accessed using slot-value.
It means that, unless specific request, defclass don't create any accessor for the slots:
> (defclass point ()
(x y))
(let ((new-point (make-instance 'point)))
(setf (point-x new-point) 1))
Error: The function (COMMON-LISP:SETF COMMON-LISP-USER::POINT-X) is undefined.
In this case, one must use the slot-value function to access or modify the slot value.
(defclass point ()
(x y))
(let ((new-point (make-instance 'point)))
(setf (slot-value new-point 'x) 1))
Obviously, when there are several slots to update, the code become a little cumbersome:
(defmethod translate ((point-instance point) delta-x delta-y)
(setf (slot-value point-instance 'x)
(+ (slot-value point-instance 'x) delta-x))
(setf (slot-value point-instance 'y)
(+ (slot-value point-instance 'y) delta-y)))
For that reason, the with-slots macro can make the code easier to read:
(defmethod translate ((point-instance point) delta-x delta-y)
(with-slots (x y) point-instance
(setf x (+ x delta-x))
(setf y (+ y delta-y))))
Yes. This (great) tutorial of 2003 has a good one from the geometry domain.
Create a class to represent points in 3-dimensions:
(defclass point ()
(x y z))
Create a variable to instantiate the class and a function to set the values:
(defvar my-point
(make-instance 'point))
(defun set-point-values (point x y z)
(setf (slot-value point 'x) x
(slot-value point 'y) y
(slot-value point 'z) z))
In the REPL, do:
CL-USER 17 > (set-point-values my-point 3 4 12)
12
Now, think about a function to compute the distance between points. A brute force way would be:
(defun brute-force-distance-from-origin (point)
(let ((x (slot-value point 'x))
(y (slot-value point 'y))
(z (slot-value point 'z)))
(sqrt (+ (* x x)
(* y y)
(* z z)))))
Using the with-slots macro:
(defun distance-from-origin (point)
(with-slots (x y z) point (sqrt (+ (* x x)
(* y y)
(* z z)))))
Calling the function in the REPL works as expected:
CL-USER> (distance-from-origin my-point)
13.0

Generate TYPECASE with macro in Common Lisp

I have a list of two element sublists which will change and grow in the course of the program. I want to write a macro which takes a key and generates a case dynamically like:
;; This is the List for saving CASE clauses
(setf l '((number 2) (symbol 3)))
;; and i want to have the following expansion
(typecase 'y
(number 2)
(symbol 3))
I could have a macro which only refers to the global l:
(defmacro m (x)
`(typecase ,x ,#l))
which would expand correctly
(m 'y) ;expands to (TYPECASE 'Y (number 2) (symbol 3))
But how can i write the macro with a parameter for the list l so that it would work with other lists as well?
;; A macro which should generate the case based on the above list
(defmacro m (x l)
`(typecase ,x ,#l))
This doesn't work since l in the arguments list i a symbol and a call to (m 'y l) will expand to (TYPECASE 'Y . L).
Wanting to adhere to typecase mechanism, my workaround was as follows:
(setf types-x '(((integer 0 *) 38)
((eql neli) "Neli in X")
(symbol 39))
)
(setf types-y '(((eql neli) "Neli in Y")
((array bit *) "A Bit Vector")))
(defmacro m (x types-id)
(case types-id
(:x `(typecase ,x ,#types-x))
(:y `(etypecase ,x ,#types-y))))
(m 'neli :x) ;"Neli in X"
(m 'neli :y) ;"Neli in Y"
(m 'foo :x) ;39
Any hints and comments is appreciated.
You don't need a macro for what you're trying to do: use a function.
For instance, given
(defvar *type-matches*
'((float 0)
(number 1)
(t 3)))
Then
(defun type-match (thing &optional (against *type-matches*))
(loop for (type val) in against
when (typep thing type)
return (values val type)
finally (return (values nil nil))))
Will match a thing against a type:
> (type-match 1.0)
0
float
> (type-match 1)
1
number
You want to keep the variables sorted by type, which you can do by, for instance:
(setf *type-matches* (sort *type-matches* #'subtypep :key #'car))
You want to keep the matches sorted of course.
If you want to delay the execution of the forms then you can do something like this (this also deals with sorting the types):
(defvar *type-matches*
'())
(defmacro define-type-match (type/spec &body forms)
;; define a type match, optionally in a specified list
(multiple-value-bind (type var)
(etypecase type/spec
(symbol (values type/spec '*type-matches*))
(cons (values (first type/spec) (second type/spec))))
(let ((foundn (gensym "FOUND")))
`(let ((,foundn (assoc ',type ,var :test #'equal)))
(if ,foundn
(setf (cdr ,foundn) (lambda () ,#forms))
(setf ,var (sort (acons ',type (lambda () ,#forms) ,var)
#'subtypep :key #'car)))
',type/spec))))
(defun type-match (thing &optional (against *type-matches*))
(loop for (type . f) in against
when (typep thing type)
return (values (funcall f) type)
finally (return (values nil nil))))
The actual problem that you face is that if you do
(setf l '((number 2) (symbol 3)))
already on toplevel, if you evaluate l, you don't come further than
((number 2) (symbol 3))
So if you use l in a macro as an argument, you can't come further
than this. But what you need is to evaluate this form (modified after adding a typecase and an evaluated x upfront) once more within the macro.
This is, why #tfb suggested to write a function which actually evaluates the matching of the types specified in l.
So, we could regard his type-match function as a mini-interpreter for the type specifications given in l.
If you do a simple (defmacro m (x l) `(typecase ,x ,#l))
you face exactly that problem:
(macroexpand-1 '(m 1 l))
;; (typecase 1 . l)
but what we need is that l once more evaluated.
(defmacro m (x l)
`(typecase ,x ,#(eval l)))
Which would give the actually desired result:
(macroexpand-1 '(m 1 l))
;; (TYPECASE 1 (NUMBER 2) (SYMBOL 3)) ;
;; T
;; and thus:
(m 1 l) ;; 2
So far, it seems to work. But somewhere in the backhead it becomes itchy, because we know from books and community: "Don't use eval!! Eval in the code is evil!"
Trying around, you will find out when it will bite you very soon:
# try this in a new session:
(defmacro m (x l) `(typecase ,x ,#(eval l)))
;; m
;; define `l` after definition of the macro works:
(setf l '((number 2) (symbol 3)))
;; ((NUMBER 2) (SYMBOL 3))
(m 1 l)
;; 2 ;; so our `eval` can handle definitions of `l` after macro was stated
(m '(1 2) l)
;; NIL
;; even redefining `l` works!
(setf l '((number 2) (symbol 3) (list 4)))
;; ((NUMBER 2) (SYMBOL 3) (LIST 4))
(m 1 l)
;; 2
(m '(1 2) l)
;; 4 ;; and it can handle re-definitions of `l` correctly.
;; however:
(let ((l '((number 2) (symbol 3)))) (m '(1 2) l))
;; 4 !!! this is clearly wrong! Expected is NIL!
;; so our `eval` in the macro cannot handle scoping correctly
;; which is a no-go for usage!
;; but after re-defining `l` globally to:
(setf l '((number 2) (symbol 3)))
;; ((NUMBER 2) (SYMBOL 3))
(m '(1 2) l)
;; NIL ;; it behaves correctly
(let ((lst '((number 2) (symbol 3) (list 4)))) (m '(1 2) lst))
;; *** - EVAL: variable LST has no value
;; so it becomes clear: `m` is looking in the scoping
;; where it was defined - the global scope (the parent scope of `m` when `m` was defined or within the scope of `m`).
So the conclusion is:
The given macro with eval is NOT working correctly!!
Since it cannot handle local scoping.
So #tfb's answer - writing a mini-evaluator-function for l is the probably only way to handle this in a proper, safe, correct way.
Update
It seems to me that doing:
(defmacro m (x l)
`(typecase ,x ,#l))
(defun m-fun (x l)
(eval `(m ,x ,l)))
(m-fun ''y l) ;; 3
(m-fun 'y l) ;; error since y unknown
(let ((l '((number 2) (symbol 3) (list 4))))
(m-fun ''(1 2) l)) ;; => 4 since it is a list
(let ((l '((number 2) (symbol 3))))
(m-fun ''(1 2) l)) ;; => NIL since it is a list
(let ((l '((number 2) (symbol 3))))
(m-fun ''y l)) ;; => 3 since it is a symbol
(let ((n 12))
(m-fun n l)) ;; => 2 since it is a number
;; to improve `m-fun`, one could define
(defun m-fun (x l)
(eval `(m ',x ,l)))
;; then, one has not to do the strangely looking double quote
;; ''y but just one quote 'y.
(let ((l '((number 2) (symbol 3) (list 4))))
(m-fun '(1 2) l)) ;; => 4 since it is a list
;; etc.
at least hides the eval within a function.
And one does not have to use backquote in the main code.
Macro expansion happens at compile time, not run time, thus if the case clause list changes over the course of the program, the macro expansion will not change to reflect it.
If you want to dynamically select an unevaluated but changeable value, you can use assoc in the expansion instead of case:
(defmacro m (x l)
`(second (assoc ,x ,l)))
Sample expansion:
(m x l)
->
(SECOND (ASSOC X L))
Output of (assoc x l) with the value of l in your question and x = 'x:
(let ((x 'x))
(m x l))
->
2
However if you did decide to do it this way, you could simplify things and replace the macro with a function:
(defun m (x l)
(second (assoc x l)))
UPDATE FOR QUESTION EDIT:
Replace assoc as follows:
(defun m (x l)
(second (assoc-if (lambda (type)
(typep x type))
l)))

Returning callable functions/closures from inside a Common Lisp macro

I want to define a macro of the following form, where each of the rules (nested in the parameter list) are recorded into a hash-table:
(proc-rule
((100 ((+ w 10) (- h 25)))
((+ ip 12) ((* w .2) (* h .1)))
((* ip 2) ((+ ix (* 2 w)) iy))
(45.5 ((+ ix (* 2 w)) iy)))
table)
These rules can contain references to specific argument names. The first list (which is also the only obligatory one!):
(100 ((+ w 10) (- h 25)))
has a head which is a value, and a tail consisting of two other expressions (which could refer to w y or not) which i add to the hash-table this way:
(setq table (make-hash-table :test #'equalp))
(defmacro proc-rule (rule table)
(destructuring-bind (ip (ix iy)) (car rule)
`(progn
;; Record the initial forms
(setf (gethash ,ip ,table) #'(lambda (w h) (list ,ix ,iy)))
;;
)))
Till now works as expected, when looking for the value 100 i get the function which i can call with arguments as w and h:
(funcall (gethash 100 table) 100 100) ; (110 75)
Now i want to iterate over the rest of the rules and add them to the table. The head of each of these rules could be an expression having reference to the head of the very first rule (called ip) or be just another fresh value (which evaluates to itself. Here is the complete macro definition again):
(defmacro proc-rule (rule table)
(destructuring-bind (ip (ix iy)) (car rule)
`(progn
;; Record the initial forms
(setf (gethash ,ip ,table) #'(lambda (w h) (list ,ix ,iy)))
;; Add the rest of the rules
(dolist (pattern (cdr rule))
(setf (gethash (car pattern) ,table)
#'(lambda (w h) (list (caadr pattern) (cadadr pattern)))))
)))
The value to this key is also a closure with again two parameters W H which also now can contain references to the passed in arguments which i have labeled as ix iy. Compiling this expansion:
(PROGN
(SETF (GETHASH 100 TABLE) #'(LAMBDA (W H) (LIST (+ W 10) (- H 25))))
(DOLIST (PATTERN (CDR RULE))
(SETF (GETHASH (CAR PATTERN) TABLE)
#'(LAMBDA (W H) (LIST (CAADR PATTERN) (CADADR PATTERN))))))
leads to a funcall error because of the unquoted ,(cdr rule):
(((+ IP 12) ((* W 0.2) (* H 0.1))) ((* IP 2) ((+ IX (* 2 W)) IY))
(45.5 ((+ IX (* 2 W)) IY)))
Changing that part to (cdr ',rule) results of course in recording quoted conses as values to the keys so that:
(funcall (gethash 45.5 table) 100 100) ;(((+ IX (* 2 W)) IY) NIL)
How could i get tails of these rules to be saved as function bodies and not conses so that calling them computes the supplied expressions?
Second question: is this all in all a good design, and if not please explain why not? (I wanted the user to supply the expressions in a more convenient form like ((+ ip 12) ((* w .2) (* h .1))).
Basic Rule for writing Macros
Write down the code you want to generate. Then write the code transforming code which generates this code.
Example
See this example for generated code - not specifically for your example, but similar - I'm also using LOOP instead of DOLIST, because it does destructuring:
(loop for ((one two)) in '((((+ a b) (- a b)))
(((- a b) (+ a b))))
collect (lambda (a b) (list one two)))
Above does not work as intended, because forms like (+ a b) are treated as lists and a variable like one does just return such a list. It also does not work because of using the iteration variables.
To address the later we could rebind them:
(loop for ((one two)) in '((((+ a b) (- a b)))
(((- a b) (+ a b))))
collect (let ((one one)
(two two))
(lambda (a b) (list one two))))
Still in above code we have lists and not code for the expressions.
If you want to create functions from source code you need to call EVAL or COMPILE:
(loop for ((one two)) in '((((+ a b) (- a b)))
(((- a b) (+ a b))))
collect (compile nil `(lambda (a b) (list ,one ,two))))
Above creates code and compiles it at runtime.
That would be code to generate. But you would generate code which explicitly calls EVAL or COMPILE. This is a typical anti-pattern. A macro creates code which then gets automatically evaluated. One rarely needs another step of evaluation - so always think whether it's possible to get rid of that added evaluation step.
But what you really want is to generate this code:
(list (lambda (a b) (list (+ a b) (- a b)))
(lambda (a b) (list (- a b) (+ a b))))
Think about how to change your macro to create fully expanded code like above.
Macro Syntax
I would name the macro differently, change the argument order and get rid of the list:
(define-proc-rules table
(100 ((+ w 10) (- h 25)))
((+ ip 12) ((* w .2) (* h .1)))
((* ip 2) ((+ ix (* 2 w)) iy))
(45.5 ((+ ix (* 2 w)) iy)))
The macro would then be defined with:
(defmacro define-proc-rules (table &body rules) ...)
Allow me to format it a bit differently:
(proc-rule ((100 ((+ w 10) (- h 25)))
((+ ip 12) ((* w .2) (* h .1)))
((* ip 2) ((+ ix (* 2 w)) iy))
(45.5 ((+ ix (* 2 w)) iy)))
table)
It seems that:
the 100 must be a literal value
the first form of each rule should be evaluated with ip bound to that first key (100)
the second form of each rule is a list of two expressions such that these forms describe a function that returns a list of evaluating these two expressions
the two parameters of these functions are always named w and h
they can also refer to ix and iy which are the two elements of the return list of the first rule function
I see two ways of accomplishing that last part:
either ix and iy are symbol macros that expand to the forms given in the first rule at macro expansion time. This would maybe be a bit hairy.
or each subsequent rule function should call the first rule function and bind ix and iy to its return list; something like this (untested sketch):
(defmacro proc-rule (rules table)
(let ((ip (first (first rules))))
`(setf ,#(loop :for (keyform expr) :in rules
:collect `(gethash (let ((ip ,ip)) ,keyform) ,table)
:collect `(lambda (w h)
(destructuring-bind (ix iy)
(funcall (gethash ,ip ,table) w h)
(declare (ignorable ix iy))
(list ,#expr)))))))
However, from personal convictions, I'd advise against these implicit bindings and try to find a better way to express these rules.

lisp macro to build a list of an expression and it's evaluation

I'm trying to write a macro in Common Lisp that takes any number of expressions and builds a list containing each expression followed by its evaluation in a single line. For example, if I name my macro as
(defmacro list-builder (&rest exp)
...)
and I run
(let ((X 1) (Y 2)) (list-builder (+ X Y) (- Y X) X))
I want it to return:
'((+ X Y) 3 (- Y X) 1 X 1)
The best I've been able to do so far is get a list of the expressions using the code
(defmacro list-builder (&rest exp)
`',#`(',exp ,exp))
INPUT: (let ((X 1) (Y 2)) (list-builder (+ X Y) (+ Y X) X))
'((+ X Y) (+ Y X) X)
Strictly speaking, the macro itself cannot do that; what the macro must do is generate code in which the argument expressions are embedded in such a way that they are evaluated, and also in such a way that they are quoted.
Given (list-builder (+ x y) (+ y x) x) we would like to generate this code: (list '(+ x y) (+ x y) '(+ y x) (+ y x) 'x x).
We can split the macro into an top-level wrapper defined with defmacro and an expander function that does the bulk of the work of producing the list arguments; The macro's body just sticks the list symbol on it and returns it.
Macro helper functions have to be wrapped with a little eval-when dance in Common Lisp to make sure they are available in all conceivable situations that the macro might be processed:
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun list-builder-expander (exprs)
(cond
((null exprs) nil)
((atom exprs) (error "list-builder: dotted syntax unsupported":))
(t (list* `',(car exprs) (car exprs)
(list-builder-expander (cdr exprs)))))))
(defmacro list-builder (&rest exprs)
(cons 'list (list-builder-expander exprs)))
A "slick" implementation, all in one defmacro, inside a single backquote expression, might go like this:
(defmacro list-builder (&rest exprs)
`(list ,#(mapcan (lambda (expr) (list `',expr expr)) exprs)))
The "dotted syntax unsupported" check we implemented before now becomes an error out of mapcan.
The lambda turns each expression E into the list ((quote E) E). mapcan catenates these lists together to form the arguments for list, which are then spliced into the (list ...) form with ,#.
The form `',expr follows from applying the quote shorthand to `(quote ,expr).
Of course, a lisp macro can do that. Since lisp macros provide full control over evaluation of their arguments.
You have to use macro helper functions only in cases in which you want to use recursion. Since macros have problems to call themselves recursively.
But by looping over the &rest rest argument, you can generate variadic macros (macros with arbitrary number of arguments) and still control the evaluation of each of its arguments.
After some trial and error cycles (macro construction is an incremental procedure, since macros are complex structures), I obtained the
"simpler" solution:
(defmacro list-builder (&rest rest)
`(list ,#(loop for x in `,rest
nconcing (list `',x x))))
Test by:
(let ((X 1)
(Y 2))
(list-builder (+ X Y) (- Y X) X))
;; ((+ X Y) 3 (- Y X) 1 X 1)
Sometimes, in loop constructs, instead of collect/collecting, use nconc/nconcing in combination with (list ...) to have more control over how the elements are consed together.
The
(list `',x x)
ensures, that the second x gets evaluated, while the first
`',x
places the content of x into the expression, while its quoting prevents the evluation of the expression placed for x.
The outer list in combination with the splicing of the loop construct into it,
finally captures (prevents) the intrinsic very final evaluation of the macro body.
(defmacro list-builder (&rest args)
`(let ((lst ',args)
(acc nil))
(dolist (v lst)
(push v acc)
(push (eval v) acc))
(nreverse acc)))
We could create the list builder macro to take rest parameters as you did (I simply renamed them as args for pseudo code). I'd create a quoted list (lst) of the expressions within the list, and an empty list (acc) to store the expressions and whatever they evaluate to later. Then we can use dolist to iterate through our list and push each expression to the list, followed by whatever it evaluates to by running eval on the expression. Then we can finally use nreverse to get the correct order for the list.
We can then call it:
(let ((x 1)
(y 2))
(declare (special x))
(declare (special y))
(list-builder (+ x y) (- y x) x))
The result will be:
((+ X Y) 3 (- Y X) 1 X 1)
CL-USER>

What is the difference between let and let*, I dont understand this (Racket) [duplicate]

This question already has answers here:
Confused by the difference between let and let* in Scheme
(2 answers)
Closed 8 years ago.
(define x 2)
(let ((x 1) (y (+ x 1))) (+ x y))
you get 4;
(let* ((x 1) (y (+ x 1))) (+ x y))
you get 3.
I do not understand how the let thing works. Could someone please explain, i'm new to computer science thanks
(let ((x 0) (z x))
...)
Is equivalent to:
((lambda (x z) ...) 0 x)
Perhaps in the anonymous procedure call you can see that when the arguments are evaluated the variable inside the body does not exist yet, but inside the body x is 0 and the previous x is shadowed in the whole body but accesible as z.
(let* ((x 0) (z x))
...)
Which is equivalent to:
(let ((x 0))
(let ((z x))
...))
Looking at this you see right away that x gets set to 0 and shadows any other x at the time z gets bound.
Imagine you want to calculate the hypothenus og a triangle:
(let ((hypotenuse (sqrt (+ (square a) (square b)))))
...)
You want to split it up a little so you change it to a let* like this:
(let* ((sqa (square a))
(sqb (square b))
(hypotenuse (sqrt sqa sqb)))
...)
If you woudl have used let then sqa and sqb wuldn't be available!
The rule of thumb is to use let and change it to a let* when you need to reference something bound in the same let. Be careful to not shadow variables you are using later.