diff --git a/common_lisp/20231123_quote_unquote.html b/common_lisp/20231123_quote_unquote.html new file mode 100644 index 0000000..dc1a8b8 --- /dev/null +++ b/common_lisp/20231123_quote_unquote.html @@ -0,0 +1,84 @@ + +
Thursday, Nov 23, 2023
+ +
+ Reading Let Over Lambda (LOL), and in Chapter 3 he demonstrates how to
+ create macros that will only evaluate a form once. The macro
+ is defmacro!
and on page 60 he gives an example of it's use and
+ the results.
+
+(defmacro! square (o!x) + `(progn + (format t "[~a gives ~a]~%") + ',o!x ,g!x) + (* ,g!x ,g!x)) ++ +
+ Note the quote-unquote (',)
preceding o!x
+
+The thing I have to remember is that macros do not evaluate the forms they are +given, but return forms to be evaluated later. +
+ +To show how this works, set a variable to a form that is quoted.
+ ++CL-USER> (defvar b '(+ 1 3)) +(+ 1 3) ++ +
The REPL returns the form unevaluated.
+ +If we use it in an expression, backquote the expression and unquote symbol B, + we will see how it expands. +
+ ++CL-USER> `(+ 1 ,b) +(+ 1 (+ 1 3)) ++ +
And if we evaluate the above it will return 5.
+ ++CL-USER> (eval `(+ 1 ,b)) +5 ++ +
BUT, if we quote-unquote it, the top-level returns:
+ ++CL-USER> `(+ 1 ',b) +(+ 1 '(+ 1 3)) ++ +
If we were to evaluate the above it would throw us into the debugger because
+ of '(+ 1 3)
+
+To evaluate it without throwing an error we need to perform two evaluations: +
+ ++CL-USER> (eval `(+ 1 (eval ',b))) +5 ++ +
+This also demonstrates how functions evaluate their arguments first BEFORE they +perform the calculations in defined in the function. +
+ +
+With macros, they do not evaluate their arguments. Macros return forms to be
+evaluated later. Thus, when a macro is given an expression (+ 1 3)
+ it needs to be unquoted in order to be evaluated at a later time (remember when
+defining macros everything is wrapped in a backquote).
+
Sunday, Nov 18, 2023
+ ++ Let Over Lambda presents a LoL that returns a list of lambda functions + for a counter variable. Somewhere around pg 32, maybe. +
+ ++(let ((counter 0)) + (values + (lamda () (incf counter)) + (lamda () (decf counter)))) ++ +
+That got me wondering how to access the values returned. I first
+tried (setf a ( ... ))
but it only gave me the first
+value,
(incf counter)+ + +
+ I tried multiple-bind-values
but read that the variables assigned
+ the functions were only accessible within the multiple-bind-values
+ binding. (Source ?? )
+
+I finally settled on: +
+ ++(setf a (multiple-value-list + (let ((counter 0)) + (values + (lambda () (incf counter)) + (lambda () (decf counter)) + (lambda () counter))))) ++ +
Then, assign each to value from the list to a variable, like this:
+ ++(defun increase-count () + (funcall (car a))) + +(defun decrease-count () + (funcall (nth 1 a))) + +(defun get-count () + (funcall (nth 2 a))) ++ +
+LoL, states that the let over lamda is essentially an object, no different from +a an object returned by a class. And it is true. If I rewrite
(set a + (...))as a function like this: + + +
+(defun counter-class (multiple-value-list + (let ((counter 0)) + (values + (lambda () (incf counter)) + (lambda () (decf counter)) + (lambda () counter))))) ++ +
+Then I can define two player count objects: player1 and player2 +
+ ++(defun player1 () (counter-class)) + +(defun player2 () (counter-class)) ++ +
+Now, to call each function within respective players object, I can write this: +
+ ++(funcall (car player1)) ; to increase player 1 +(funcall (nth 1 player1)) ; to decrease count for player 1 +(funcall (nth 2 player1)) ; to return the current value of count for player1 ++ +
And of course I could do the same for player 2
+ +But this is kind of ugly so I could create functions for each player
+ ++(defun player1.incf () + (funcall (car player1))) + +(defun player1.decf () + (funcall (nth 1 player1))) + +(defun player1.get () + (funcall (nth 2 player1))) ++ +
I would have to do the same for player2, which would be kind of tedious.
+ +According to Graham and Hoyte, copying code begs to be made into a macro. + Which I will return to later once I have a better understanding of how to + write macros. +