には、あなたが求めることを正確にdash.el
行う関数があります:-separate
(-separate 'evenp '(1 2 3 4)) ; => '((2 4) (1 3))
を使用する場合は、投稿の残りの部分を無視できます-separate
。Haskell のパーティション関数をElispに実装する必要がありました。Elisp は多くの点で Common Lisp に似ている1ため、この回答は両方の言語のコーダーに役立ちます。私のコードは、Python の同様の実装に触発されました
(defun partition-push (p xs)
(let (trues falses) ; initialized to nil, nil = '()
(mapc (lambda (x) ; like mapcar but for side-effects only
(if (funcall p x)
(push x trues)
(push x falses)))
xs)
(list (reverse trues) (reverse falses))))
(defun partition-append (p xs)
(reduce (lambda (r x)
(if (funcall p x)
(list (append (car r) (list x))
(cadr r))
(list (car r)
(append (cadr r) (list x)))))
xs
:initial-value '(() ()) ; (list nil nil)
))
(defun partition-reduce-reverse (p xs)
(mapcar #'reverse ; reverse both lists
(reduce (lambda (r x)
(if (funcall p x)
(list (cons x (car r))
(cadr r))
(list (car r)
(cons x (cadr r)))))
xs
:initial-value '(() ())
)))
push
リストする要素を先頭に追加する破壊的な関数です。add-to-list
同じ要素を一度しか追加しないため、Elisp の は使用しませんでした。結果を蓄積しないmapc
マップ関数2です。Elisp は、Common Lisp と同様に、関数と変数に対して別々の名前空間を持っているため3funcall
、パラメーターとして受け取った関数を呼び出すために使用する必要があります。は、キーワードを受け入れるreduce
高次関数4:initial-value
であり、さまざまな使い方が可能です。append
可変量のリストを連結します。
このコードでは、普及している「プッシュ アンドリバース」イディオムpartition-push
を使用する命令的な Common Lisp が使用されています。リストに 1 回追加すると、リストはコンス セルとして実装されるため、項目を追加すると. 最後に追加することを示しています。私は関数型プログラミングのファンなので、副作用のないバージョンをin で書きました。O(1)
O(n)
O(n)
n
O(n²)
partition-append
reduce
partition-reduce-reverse
Emacs にはプロファイリング ツールがあります。これら3つの関数に対して実行します。返されるリストの最初の要素は、合計秒数です。ご覧のとおり、リストへの追加は非常に遅く動作しますが、機能的なバリアントは最も高速です。
ELISP> (benchmark-run 100 (-separate #'evenp (number-sequence 0 1000)))
(0.043594004 0 0.0)
ELISP> (benchmark-run 100 (partition-push #'evenp (number-sequence 0 1000)))
(0.468053176 7 0.2956386049999793)
ELISP> (benchmark-run 100 (partition-append #'evenp (number-sequence 0 1000)))
(7.412973128 162 6.853687342999947)
ELISP> (benchmark-run 100 (partition-reduce-reverse #'evenp (number-sequence 0 1000)))
(0.217411618 3 0.12750035599998455)
参考文献
- Common Lisp と Emacs Lisp の違い
- 高階関数のマッピング
- 機能細胞と価値細胞の分離の技術的課題
- 高階関数の折り畳み