要问 Lisp 为什么那么强大,答案就是 Macro。
Lisp 的 Macro 是图灵完备的,你可以使用 Macro 来扩展 Lisp 语言本身,可以定义各种 DSL 来满足自己的业务需求。对于 Emacs 配置而言,使用 Use-package 插件提供的 DSL,可以极大地简化你的 Emacs 配置,让你的配置更加有条理,同时合理使用 Use-package 的延迟加载可以提高你的 Emacs 启动速度。
不多说,直接看视频吧。
-
Youtube: - YouTube
视频 outline:
Spacemacs Rocks Season 2 (Day 9)
Topic: Macro and Use-package
What is macro?
Code which generate code?
(setq my-var 1)
(setq my-var (+ 1 my-var))
(defmacro inc (var)
(list 'setq var (list '1+ var)))
(inc my-var) ;;add a new language
(macroexpand '(inc my-var))
(defun inc-v2 (var)
(setq var (1+ var)))
(inc-v2 my-var)
(setq my-var 1)
(macroexpand '(inc my-var))
Write macro is almost the same as writing function in elisp.
What’s the different betwwen function and macro?
-
Evaluation: the macro arguments are the actual expressions appearing in the macro call.
-
Expansion: the value returned by the macro body is an alternate Lisp expression, also known as the expansion of the macro
A few examples:
back quote matters.
(sp-local-pair 'emacs-lisp-mode "`" nil :actions nil)
(defun my-print (number)
(message "This is a number: %d" number))
(my-print 2)
(my-print (+ 2 3))
(quote (+ 1 1))
;; return a list
(defmacro my-print-2 (number)
`(message "This is a number; %d" ,number))
(my-print-2 2)
(my-print-2 (+ 2 3))
(setq my-var 2)
(inc my-var)
(defmacro inc2 (var1 var2)
(list 'progn (list 'inc var1) (list 'inc var2)))
(macroexpand '(inc2 my-var my-var))
(macroexpand-all '(inc2 my-var my-var))
Why Macro?
A more useful example of Elisp macro
(defun prelude-search (query-url prompt)
"Open the search url constructed with the QUERY-URL.
PROMPT sets the `read-string prompt."
(browse-url
(concat query-url
(url-hexify-string
(if mark-active
(buffer-substring (region-beginning) (region-end))
(read-string prompt))))))
(defmacro prelude-install-search-engine (search-engine-name search-engine-url search-engine-prompt)
"Given some information regarding a search engine, install the interactive command to search through them"
`(defun ,(intern (format "prelude-%s" search-engine-name)) ()
,(format "Search %s with a query or region if any." search-engine-name)
(interactive)
(prelude-search ,search-engine-url ,search-engine-prompt)))
(prelude-install-search-engine "google" "http://www.google.com/search?q=" "Google: ")
(prelude-install-search-engine "youtube" "http://www.youtube.com/results?search_query=" "Search YouTube: ")
(prelude-install-search-engine "github" "https://github.com/search?q=" "Search GitHub: ")
(prelude-install-search-engine "duckduckgo" "https://duckduckgo.com/?t=lm&q=" "Search DuckDuckGo: ")
##Use-package and basic usage
###a more safe require
group config into one place
autoload and bind keys easily
make your config load faster
and more? Spacemacs use it a lot.
Bonus Time
- pretty print the lisp Object
(pp (macroexpand '(use-package company-mode)))
- fuck your brain?
(defmacro defsynonym (old-name new-name)
`(defmacro ,new-name (&rest args)
`(, ',old-name ,@args)))
more discussion: lisp中的`与,是怎么用的?
Reference
Readme more about macro: Macros (GNU Emacs Lisp Reference Manual)