201 lines
5.1 KiB
Common 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
|