Last active
April 14, 2019 20:48
-
-
Save ltbringer/b59cf491ce80a9fc6fe0e2aaaf07c7fa to your computer and use it in GitHub Desktop.
Common Lisp: Easy macro introduction
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; ============================================================= | |
;; A file simulator is used to create an example problem | |
;; that helps demonstrate the use of macros in common lisp | |
;; ============================================================= | |
;; Interfaces to file I/Os expose methods like | |
;; `open`, `close`, `read` | |
;; not closing a file can lead to issues where the machine runs | |
;; out of memory, or unreliable state of the file | |
;; (due to unwanted side-effects) | |
;; | |
;; ------------------------------------ | |
;; try { | |
;; file = File("/path/to/file").open() | |
;; data = file.read() | |
;; } catch (...) { | |
;; ... | |
;; } finally { | |
;; file.close() | |
;; } | |
;; ------------------------------------ | |
;; | |
;; The above pseudo-code is therefore a common pattern, | |
;; luckily languages provide syntactic sugar for the same | |
;; for example, Python's `with` | |
;; | |
;; ------------------------------------ | |
;; with open("path/to/file", "mode") as f: | |
;; data = f.read() | |
;; ------------------------------------ | |
;; | |
;; A clearer syntax which even closes the file for us | |
;; Let's imagine that such syntax is not available in clisp | |
;; and create the same using clisp macros | |
(defclass file-sim () | |
;; -bytes: An array of bits in the file | |
;; -state: "open" if the file can be read / "closed" if the file is closed | |
((bytes | |
:initarg :bytes) | |
(state | |
:initarg :state))) | |
(defmethod open-file ((file file-sim)) | |
;; method to change the state of the file | |
(print "open") | |
(setf (slot-value file 'state) "open")) | |
(defmethod read-file ((file file-sim)) | |
;; method to read the bytes in the file | |
(cond | |
;; Check the state of the file | |
((equal (slot-value file 'state) "open") (print (slot-value file 'bytes))) | |
((equal (slot-value file 'state) "closed") "Use the open-file method on the file before reading"))) | |
(defmethod close-file ((file file-sim)) | |
;; method to change the state of the file to "closed" | |
(print "closed") | |
(setf (slot-value file 'state) "closed")) | |
;; ============================================================= | |
;; To do the same using a function we would write something like | |
;; ------------------------------------ | |
;; (defun (file) | |
;; (progn | |
;; (open-file file) | |
;; (read-file file) | |
;; (close-file file))) | |
;; ------------------------------------ | |
;; To create a macro that outputs this particular function's | |
;; code, we can use the (`)[backticks] to create the | |
;; template and fill in the variables using (,)[comma] | |
;; @body allows us to add in any method other than `read-file` | |
;; ============================================================= | |
(defmacro with (file &body body) | |
`(progn | |
(open-file ,file) | |
,@body | |
(close-file ,file))) | |
;; ============================================================= | |
;; Now we can use this macro like: | |
;; ------------------------------------ | |
;; (with *test-file* | |
;; (read-file *test-file*)) | |
;; ------------------------------------ | |
;; ============================================================= |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment