关于Dash.el 里几个函数/宏的用法

dash.el里有几个函数,看了文档和例子,还是不知道是干嘛的。。有谁可以总体讲解一下不?

Threading macros

  • -> (x &optional form &rest more)
  • ->> (x &optional form &rest more)
  • –> (x &rest forms)
  • -as-> (value variable &rest forms)
  • -some-> (x &optional form &rest more)
  • -some->> (x &optional form &rest more)
  • -some–> (x &optional form &rest more)

M-x ielm

都是宏,把给的例子展开,再对照文档就好明白了。比如

(-> '(2 3 5) (append '(8 13)))

展开

(append '(2 3 5) '(8 13)))

这跟 Emacs 25.1 自带的 thread-first 是同样的作用。

后面 -fix 之类才难以理解,不过估计也用不上,也无所谓。

1 个赞

前段时间我给很多 Emacs Lisp 函数加注了例子(见 GitHub - xuchunyang/elisp-demos: Demonstrate Emacs Lisp APIs ),我给 -> 加的例子是:

#+BEGIN_SRC elisp
;; (/ (- 5 1) 2)
(-> 5 (- 1) (/ 2))
#+END_SRC

#+RESULTS:
: 2
4 个赞
(-> 1 (+ 2) (- 3) (/ 4))
;; = (/ (- (+ 1 2) 3) 4)

后面几个都类似。用来避免 nested parenthesis 的语法糖

2 个赞

:joy:感谢,我都忘了有expand这一回事了。。

dash.el 就是为了消除嵌套调用。

例如通过 append 一个个数字,生成列表,使用传统的写法:

(append (append (append '(1) '(2)) '(3)) '(4))
;; (append
;;  (append
;;   (append
;;    '(1)
;;    '(2))
;;   '(3))
;;  '(4))

;; => (1 2 3 4)

dash.el 的写法:

(-> '(1) (append '(2)) (append '(3)) (append '(4)))
;; (-> '(1)
;;  (append '(2))
;;  (append '(3))
;;  (append '(4)))

;; => (1 2 3 4)

是不是有点 js 中的回调嵌套 vs 链式调用的感觉?

-> 的作用是,把它的第一个参数推给第二个参数(form),并作为该 form 的第一个参数。执行结果再推给下一个 form…

(-> '(1) ;; => -------------.
    ;;                      |
    ;;      .---------------'
    ;;      |
    ;;      v
    (append   '(2)) ;; => --.
    ;;                      |
    ;;      .---------------'
    ;;      |
    ;;      v
    (append   '(3)) ;; => --.
    ;;                      |
    ;;      .---------------'
    ;;      |
    ;;      v
    (append   '(4)))

;; => (1 2 3 4)

->> 的作用是把第一个参数推给 forms 作为最末参数,所以得到的结果刚好相反:

(->> '(1) ;; => ------------.
    ;;                      |
    ;;           .----------'
    ;;           |
    ;;           v
    (append '(2)  ) ;; => --.
    ;;                      |
    ;;           .----------'
    ;;           |
    ;;           v
    (append '(3)  ) ;; => --.
    ;;                      |
    ;;           .----------'
    ;;           |
    ;;           v
    (append '(4)  ))

;; => (4 3 2 1)

了解函数用法最优先当然是去看 README 中的例子,如果没看明白,或者想进一步了解,就看源代码或者如 @xuchunyang 说的,展开看结果。

不过并非所有的函数都是宏,比如 --first 是宏,但 -first 却不是。

阅读展开之后的代码也是需要一点耐心:

(macroexpand-all '(--first (evenp it) '(1 2 3)))
;; =>
;; (let
;;     (needle)
;;   (let
;;       ((list
;;         '(1 2 3))
;;        (continue t)
;;        (it-index 0))
;;     (while
;;         (and list continue)
;;       (let
;;           ((it
;;             (car list)))
;;         (if
;;             (not
;;              (not needle))
;;             (setq continue nil)
;;           (if
;;               (evenp it)
;;               (progn
;;                 (setq needle it)))))
;;       (setq it-index
;;             (1+ it-index))
;;       (setq list
;;             (cdr list))))
;;   needle)
6 个赞