Created
March 29, 2013 09:16
-
-
Save dbushenko/5269742 to your computer and use it in GitHub Desktop.
This file contains 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
(ns lection03.core) | |
;; Eval | |
(eval '(+ 1 2)) | |
(defn my-pre-macro1 [a b] | |
(eval (list '+ a b))) | |
(my-pre-macro1 1 2) | |
;; Macros | |
(defmacro my-macro1 [a b] | |
`(+ ~a ~b)) | |
(my-macro1 1 2) | |
(macroexpand-1 '(my-macro1 1 2)) | |
;; Время выполнения и время компиляции | |
(defmacro my-macro1a [a b] | |
(println "Hello from macro!") | |
`(+ ~a ~b)) | |
(macroexpand-1 '(my-macro1a 1 2)) | |
(my-macro1a 1 2) | |
;; Полностью развернуть все вложенные макросы | |
(require '[clojure.walk :as w]) | |
(macroexpand '(cond a b c d)) | |
(w/macroexpand-all '(cond a b c d)) | |
;; Использование определённых | |
;; ранее значений | |
(def abc 17) | |
(defmacro my-macro2 [a] | |
`(println ~(+ abc a))) | |
(my-macro2 4) | |
(macroexpand-1 '(my-macro2 4)) | |
;; Использование определённых | |
;; ранее функций | |
(defn my-compute1 [a b] | |
(+ a b)) | |
(defmacro my-macro3 [a b] | |
`(println ~(my-compute1 a b))) | |
(macroexpand-1 '(my-macro3 1 2)) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Синтаксис макросов | |
;; | |
;; quote и syntax-quote | |
;; ssyntax-quote полностью квалифицирует символы | |
'abc | |
`abc | |
'my/abc | |
`my/abc | |
;; Такая квалификация символов по умолчанию позволяет гарантировать, что макрос не сгенерирует код, который по оплошности сошлется или переопределит значение, уже имеющее имя в контексте, где оно используется. | |
;; unquote и unquote-splicing | |
`(println abc) | |
`(println ~abc) | |
(def cde [1 2 3]) | |
`(println ~cde) | |
`(println ~@cde) | |
;; Лексическая и динамическая область видимости | |
(def b 50) | |
(defn myprint [] | |
(println b)) | |
(myprint) | |
(let [b 20] | |
(myprint)) | |
;;--------------- | |
(def ^:dynamic t 50) | |
(defn myprint2 [] | |
(println t)) | |
(myprint2) | |
(binding [t 20] | |
(myprint2)) | |
;; Гигиена макросов | |
(def x 17) | |
(defmacro my-macro4 [] | |
(let [x 28] | |
`(println ~x))) | |
(my-macro4) | |
(macroexpand '(my-macro4)) | |
(defmacro my-macro5 [] | |
`(let [x 28] | |
(println ~x))) | |
(my-macro5) | |
(macroexpand '(my-macro5)) | |
(defmacro my-macro6a [] | |
(let [xx (symbol "x")] | |
`(let [~xx 28] | |
(println ~xx)))) | |
(macroexpand '(my-macro6a)) | |
(defmacro my-macro6 [] | |
(let [xx (gensym "x")] | |
`(let [~xx 28] | |
(println ~xx)))) | |
(my-macro6) | |
(macroexpand '(my-macro6)) | |
(defmacro my-macro7 [] | |
`(let [x# 28] | |
(println x#))) | |
(my-macro7) | |
(macroexpand '(my-macro7)) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Когда использовать макросы | |
;; Примеры макросов | |
;; | |
;; 1. Создание inline-функций | |
(defmacro my-compute2 [a b] | |
(let [x (* 2 (+ a b))] ;; inline computation (compile time) | |
`(println ~x))) | |
(my-compute2 1 2) | |
(macroexpand-1 '(my-compute2 1 2)) | |
;; 2. Вычисление условных выражений | |
(defn unless* [pred body] | |
(if (not pred) body)) | |
(unless* (> 2 1) (println "True!")) | |
(unless* (< 2 1) (println "False!")) | |
(defmacro unless [pred body] | |
`(if (not ~pred) ~body)) | |
(unless (> 2 1) (println "True!")) | |
(unless (< 2 1) (println "False!")) | |
;; 3. Привязка значений к символам, cоздание переменных и функций | |
(defmacro defn-with-compl [name args pred & body] | |
`(do (defn ~name ~args (if ~pred ~@body)) | |
(defn ~(symbol (str name "*")) ~args (if-not ~pred ~@body)))) | |
(defn-with-compl greater-than [a b] (> a b) | |
(println "Really greater!")) | |
(greater-than 2 1) | |
(greater-than 1 2) | |
(greater-than* 2 1) | |
(greater-than* 1 2) | |
;; 4. Создание нового окружения | |
;; Анафорический макрос | |
(defmacro alet [comput pred & body] | |
(let [it-symb (symbol "it")] | |
`(let [~it-symb ~comput] | |
(if ~pred | |
~@body)))) | |
(alet (+ 2 3 4) | |
(> it 7) | |
(println (+ it 10))) | |
;; ------------------ | |
(def ^:dynamic z 17) | |
(defn get-user-input [] "Hello!") | |
(defmacro my-macro8 [& body] | |
`(binding [z ~(get-user-input)] | |
~@body)) | |
(my-macro8 (println z)) | |
;; 5. Анализ и преобразование исходного кода | |
(defn inl2 [args acc] | |
(cond | |
(>= (count args) 2) (recur (drop 2 args) | |
(concat (list (first args)) | |
(list acc) (list (second args)))) | |
:else acc)) | |
(defn inl3 [[a op b & args]] | |
(inl2 args (list op a b))) | |
(defmacro inline [& args] | |
(let [res (inl3 args)] | |
`~res)) | |
;; Code walker | |
(use 'clojure.walk) | |
(defn with-inline-computations* [code] | |
(postwalk | |
(fn [c] | |
(if (and (list? c) | |
(or | |
(contains? (apply hash-set c) '+) | |
(contains? (apply hash-set c) '-))) | |
(cons 'inline c) | |
c)) | |
code)) | |
(defmacro with-inline-computations [& body] | |
(let [res (with-inline-computations* body)] | |
`(do ~@res))) | |
(macroexpand-1 | |
'(with-inline-computations | |
(let [my-val (1 + 2 - 3 + 4 - 5)] | |
(println my-val)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment