Last active
March 14, 2019 18:34
-
-
Save lgessler/50a097db40bd5f63f2ee3cfa550171dd to your computer and use it in GitHub Desktop.
Clojure macro demo for Anish
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
| ;; Preliminaries ------------------------------------------------------------ | |
| ;; Clojure has namespaces. vars can be created in namespaces and referenced | |
| ;; from other namespaces. | |
| (ns glam.db) ;; Switch into namespace glam.db | |
| (var x 1) ;; define var glam.db/x | |
| x ;; `x` evals to 1 | |
| ;;=> 1 | |
| (ns glam.other) ;; switch to other namespace | |
| x | |
| ;;ERROR: x is not defined in this namespace or imported | |
| glam.db/x ;; can access other namespaces' vars this way | |
| ;;=> 1 | |
| ;; can also import from other namespaces when entering a namespace | |
| (ns glam.other | |
| (require [glam.db :refer [x]])) | |
| x | |
| ;;=> 1 | |
| ;; The problem ------------------------------------------------------------ | |
| (ns glam.db | |
| (:require [cljs.spec.alpha :as s]) | |
| (:require-macros [cljs.spec.alpha :as s])) | |
| ;; I often needed to write something like this. (::foo is syntax for "take | |
| ;; a keyword :foo and put the current namespace in front of it, so in this | |
| ;; case, ::foo => :glam.db/foo) | |
| (def foo ::foo) | |
| (s/def ::foo string?) | |
| ;; Writing this over and over is verbose. One approach would be to write | |
| ;; a function that does this: | |
| (ns glam.db.common-functions | |
| (defn def-with-spec | |
| [key pred] | |
| (def (-> key name symbol) key) | |
| (s/def key pred)) | |
| ;; But this doesn't work for reasons that have to do with how `def` is | |
| ;; implemented. | |
| ;; We need to write a macro instead: | |
| (defmacro def-with-spec | |
| [key pred] | |
| `(do | |
| (def ~(-> key name symbol) ~key) | |
| (s/def ~key ~pred))) | |
| ;; Skipping over what all those symbols mean, this has the end result that | |
| ;; an invocation of it will expand to what we want: | |
| (def-with-spec ::foo string?) | |
| ;;macroexpand=> | |
| (do | |
| (def foo ::foo) | |
| (s/def ::foo string?)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment