common-lisp-study/macro-and-compilartion.lisp

201 lines
5.1 KiB
Common Lisp

(setf a 0)
(incf a)
(macroexpand-1 '(incf a))
(macroexpand-1 '(pop x))
(macroexpand-1 '(defstruct starship
(name nil)
(condition 'green)))
(defmacro simple-incf (a)
(list 'setq a (list '+ a 1)))
(simple-incf a)
;;; difference with a function
(defun faulty-incf (a)
(setq a (+ a 1)))
(faulty-incf a)
;; for function call 'a is being evaluated to 10, and bound to a local variable
;; then we change value of that local variable, but external is not affected
;;
;; in macros, symbol a is not evaluated, and inserted into a lisp expression,
;; that ultimately changes value of the correct variable
;;; backquote, allows for dequoting with ,
`(hello ,a world! quoted (+ 10 1 2) unquoted ,(+ 10 1 2))
;; exercise
(defmacro set-mutual (a b)
`(progn
(setq ,a ',b)
(setq ,b ',a)))
(set-mutual yo hei)
yo
hei
(set-mutual val1 val2)
(defun f (x y)
(showvar x)
(showvar y)
(* x y))
(defmacro showvar (x)
`(format t "~&Value of ~S is ~S" ',x ,x))
(showvar yo)
(f 15 4)
;;; Splicing with backquote
(setf name 'fred)
(setf address '(16 maple drive))
`(,name lives in ,address now) ; inserting
;; => (FRED LIVES IN (16 MAPLE DRIVE) NOW)
`(,name lives in ,@address now) ; splicing
;; => (FRED LIVES IN 16 MAPLE DRIVE NOW)
;; example of usage
(defmacro set-zero (&rest variables)
`(progn ,@(mapcar #'(lambda (var)
(list 'setf var 0))
variables)
'(zeroed ,@variables)))
(set-zero a b c d)
(defmacro variable-chain (&rest variables)
`(progn ,@(mapcar #'(lambda (first second)
`(setq ,first ',second))
variables
(rest variables))))
;; i even like my solution more thatn one in the book, with DO
(variable-chain a b c d)
(setf my-test-variables '(a b c d))
(mapcar (lambda (first second) (setf first second))
my-test-variables
(rest my-test-variables))
;;; Compilation
'(you can use #'compile and #'compile-file)
(defun tedious-sqrt (n)
(dotimes (i n)
(if (> (* i i) n) (return i))))
(tedious-sqrt 17)
(time (tedious-sqrt 100000000000000000))
;;; &body lambda list keyword
(defmacro whille (test &body body)
`(do ()
((not ,test))
,@body))
(defvar i)
(setf i 0)
(whille (> 5 i)
(format t "~&calculating and mutating i = ~S" i)
(incf i))
;;; well, i had warning, but things actually worked.
;; some editors treat &body differently
;; by specializing formatting / identing
;; and also signals to programmers intend, that's it's a lisp expresison
;;; DESCTRUCTURING inputs to macro
(defmacro mix-and-match-1 (pair1 pair2)
(let ((x1 (first pair1))
(y1 (second pair1))
(x2 (first pair2))
(y2 (second pair2)))
`(list '(,x1 ,y1)
'(,x1 ,y2)
'(,x2 ,y1)
'(,x2 ,y2))))
(mix-and-match-1 (fred wilma) (tony bony))
;; but, we coult treat arguments as lists where we define marco
(defmacro mix-and-match-2 ((x1 y1) (x2 y2))
`(list '(,x1 ,y1)
'(,x1 ,y2)
'(,x2 ,y1)
'(,x2 ,y2)))
(mix-and-match-2 (fred wilma) (tony bony))
;; and what would happen if it wasn't exact match with list of 2 elements?
(mix-and-match-2 (fred wilma caddy) (tony bony))
;; it fails with some check error
;;; example in the book about macro DOVECTOR
;;; So, what's that about Dynamic scoping & Lexical scoping?
;; wow, i think I understand
;; step 1: get two variables, one lexical - fished, one dynamic - birds
(setf fishes '(salmon trout))
(defvar birds)
(setf birds '(eagle parrot))
(defun show-fishes ()
fishes)
(show-fishes)
(defun show-birds ()
birds)
(show-birds)
(defun see-lexical-scoping (fishes)
`(local ,fishes and from #'show-fishes - ,(show-fishes)))
(see-lexical-soping '(kilka akula))
(defun see-dynamic-scoping (birds)
`(local ,birds and from #'show-birds - ,(show-birds)))
(see-dynamic-scoping '(sova dyatel))
;; when I called #'show-birds from inside #'see-dynamic-scoping
;; it didn't go to the top level for value of 'birds
;; the value for 'birds was taken from previous "redefinition"
;; i.e any time we enter a funtion that defined dynamicly scoped variable
;; value of that variable, until we return from the funtion, is taken from it
#'defvar ; when something could be assigned
#'defparameter ; settings, not assigned, to change reeval defparameter
#'defconstant ; should never change
;;; use for special variable
*print-base* ; if we override it as parameter for our function
; then FORMAT would pick up that value
(defun print-in-base (*print-base* x)
(format t "~&I'm printing ~D as ~S in base ~D" x x *print-base*))
;; if I use ~S to print *print-base*, then 2 in base 2 is 10, 12 in base 12 is 10. lol
(print-in-base 10 65)
(print-in-base 2 65)
(print-in-base 3 65)
(print-in-base 12 22)
;; dynamic variable accepts changes from called functions, while scope that
;; rebound it is alive can be used to communicate information between parts of
;; system. that's quite complicated