幫你精通Emacs:從JavaScript學(xué)會 elisp
對我們 JS 用戶而言,學(xué)習(xí) Emacs Lisp 似乎很難,但是這一切都是昨日煙云。因為 elisp 雖然古老,但是 library 與時俱進(jìn)。當(dāng)我們從 elisp 功勛卓著的 dash.el 起手,一秒鐘就會寫 elisp。
閑話少敘,直接切入正題。
dash.el 是 專門處理給 elisp 用戶處理數(shù)組的工具,其與 JS 的 array 一一對應(yīng)總結(jié)如下:
分為1)數(shù)組轉(zhuǎn)換(迭代式) 2) 數(shù)組轉(zhuǎn)換(非迭代式)3)邏輯判斷 4) 操作數(shù)據(jù)結(jié)構(gòu) 5)排序 五個方面。
一、迭代方法數(shù)組變形 Transform (pure function without side effecs)
函數(shù)式編程最關(guān)鍵的一點是無須關(guān)注iteration的dirty-details,此處歸類函數(shù)式迭代的方法,將 JS 的 array 方法與 elisp 的 bash.el 庫一一對應(yīng):
- ;; 1. reuduce
 - (-reduce-from (lambda (acc val) (+ acc val))
 - 0
 - '(4 7 8 10))
 - ;; => 29
 - ;; 2.map
 - (-map (lambda (val) (* val 2))
 - '(4 7 8 10))
 - ;; => (8 14 16 20)
 - ;; 3.flat
 - (-flatten-n 2 '((1 2) ((3 4) ((5 6)))))
 - ;; => (1 2 3 4 (5 6))
 - ;; 4.flatMap with no couterpart
 - ;; 5.repeat as fill
 - ELISP> (-repeat 10 0)
 - (0 0 0 0 0 0 0 0 0 0)
 - ;; 6.each with side effects
 - (-each '("x" "y" "z")
 - (lambda (val) (princ val)))
 - ;; => "xyz"
 
二、非迭代方法數(shù)組變形 non-side-effects
以上6種為函數(shù)式的迭代純函數(shù)對數(shù)組做變形 transform, 此處將非迭代方法的純函數(shù)單獨拎出來歸類:
- ;; 1.concat
 - (-concat '("x" "y" "z") '( 3 5 6))
 - ;; => ("x" "y" "z" 3 5 6)
 - ;; 2.format for join
 - (format "%s" '("x" "y" "z"))
 - ;; => "(x y z)"
 - ;; 3.slice
 - (-slice '("x" "y" "z" "w") 1 3)
 - ;; => ("y" "z")
 
三、數(shù)組的邏輯判斷 logic-predicates (non-side-effect)
函數(shù)范式的六個methods之后,我們繼續(xù)考察用于邏輯判斷的高階函數(shù):
- ;; 1.-filter as js filter
 - (-filter (lambda (v) (and (> v 30) (< v 100)))
 - '(23 76 98 10))
 - ;; => (76 98)
 - ;; 2. find or first as js find
 - (-find (lambda (v) (and (> v 30) (< v 100)))
 - '(23 76 98 10))
 - ;; => 76
 - ;; 3. -find-index as js findIndex
 - (-find-index (lambda (v) (and (> v 30) (< v 100)))
 - '(23 76 98 10))
 - ;; => 1
 - ;; 4.contains-p as js includes
 - (-contains-p '(23 76 98 10) 76)
 - ;; t
 - ;; 5. -elem-index as indexOf
 - (-elem-index 76 '(23 76 98 10))
 - ;; => 1
 - ;;6.some
 - (-some (lambda (v) (and (> v 30) (< v 100)))
 - '(23 76 98 10))
 - ;; => t
 - ;;7.every
 - (-every (lambda (v) (and (> v 30) (< v 100)))
 - '(23 76 98 10))
 - ;; => false
 
四、數(shù)據(jù)結(jié)構(gòu)操作
Array可以作為兩種抽象結(jié)構(gòu)數(shù)據(jù)的載體:分別為 stack 和 queue。
1) push 2) pop 3) shift 4) unshift 5)splice(splice屬于特殊方法,因為更改了原數(shù)組,放在此處)
- ;;1.append element to the end of array (array.push)
 - (append '(23 76 101 89) 67)
 - ;; => (23 76 101 89 . 67)
 - ;;2.nbutlast to remove last element(array.pop)
 - (nbutlast '(23 76 101 89))
 - ;; => (23 76 101)
 - ;;3.remove first element(array.shift)
 - ELISP> (let ((l '(23 76 89)))
 - (pop l)
 - l)
 - (76 89)
 - ;;4. add element to the front (array.unshift)
 - ELISP> (let ((l '(23 76 89)))
 - (push 12 l)
 - l)
 - (12 23 76 89)
 - ;;5.insert to list at position n (array.splice)
 - (-insert-at 1 'x '(a b c)) ;; => (a x b c)
 - ;;let arr = [a, b, c]; arr.splice(1, 0, x); arr
 - ;;6.replace at potion (array.splice)
 - (-replace-at 0 9 '(0 1 2 3 4 5)) ;; => (9 1 2 3 4 5)
 - ;;let arr = [1, 2, 3, 4, 5]; arr.splice(0, 1, 9); arr
 
五、數(shù)組排序
最后以無處而不在的排序收尾,無論是 sort 還是 reverse 都直接在原數(shù)組上修改,也就是 inplace 操作。
- (-sort '< '(3 1 2)) ;; => (1 2 3)
 - (-sort '> '(3 1 2)) ;; => (3 2 1)
 - ;; 完全就是
 
六、總結(jié)
通過以上總結(jié),我們發(fā)現(xiàn),即使不看文檔,也能立刻上手開始寫 elisp。


















 
 
 





 
 
 
 