- loop 20160813.707(in MELPA)
- friendly imperative loop structures
概要
Emacsの素のループ制御構造は単体ではループを中断する機能が用意されていません。
たいていの言語には組み込みで用意されていますが、
Emacs Lispで実現するためにはcatchで囲む必要があって面倒です。
そこで loop.el はbreak/continue/returnが使えるループ制御構造を用意します。
標準で用意されているCommon Lispのloopマクロ cl-loop を使えば書けるものですが、
loopマクロに苦手意識を持つならば使ってみてはいかがでしょうか。
慣れ親しんだ感覚でループが記述できるのは安心感があります。
各定義は簡単なマクロになっているので、ソースコードを読んでみると勉強になります。
インストール
パッケージシステムを初めて使う人は
以下の設定を ~/.emacs.d/init.el の
先頭に加えてください。
(package-initialize) (setq package-archives '(("gnu" . "http://elpa.gnu.org/packages/") ("melpa" . "http://melpa.org/packages/") ("org" . "http://orgmode.org/elpa/")))
初めてloopを使う方は
以下のコマンドを実行します。
M-x package-install loop
アップグレードする方は、
以下のコマンドでアップグレードしてください。
そのためにはpackage-utilsパッケージが必要です。
M-x package-install package-utils (初めてアップグレードする場合のみ) M-x package-utils-upgrade-by-name loop
使用例 160825054100.loop.el(以下のコードと同一)
;;; 0〜9の総和 (let ((x 0) (sum 0)) (loop-while (< x 10) (setq sum (+ sum x)) (setq x (1+ x))) sum) ; => 45 (cl-loop with x = 0 with sum = 0 while (< x 10) do (setq sum (+ sum x)) (setq x (1+ x)) finally return sum) ; => 45 (cl-loop for x from 0 below 10 sum x) ; => 45 ;;; 0〜5の総和 (let ((x 0) (sum 0)) (loop-while (< x 10) (setq sum (+ sum x)) (setq x (1+ x)) (when (= x 6) (loop-break))) sum) ; => 15 (cl-loop with x = 0 with sum = 0 while (< x 10) do (setq sum (+ sum x)) (setq x (1+ x)) when (= x 6) return sum) ; => 15 (cl-loop with sum = 0 for x from 0 below 10 when (= x 6) return sum do (setq sum (+ sum x))) ; => 15 ;;; 1+3+4+5 (let ((x 0) (sum 0)) (loop-while (< x 5) (setq x (1+ x)) (when (= x 2) (loop-continue)) (setq sum (+ sum x))) sum) ; => 13 (cl-loop with x = 0 with sum = 0 while (< x 5) do (setq x (1+ x)) if (= x 2) do (ignore) else do (setq sum (+ sum x)) finally return sum) ; => 13 ;;; do-while (let ((x 0) (sum 0)) ;; our condition is false on the first iteration (loop-do-while (and (> x 0) (< x 10)) (setq sum (+ sum x)) (setq x (1+ x))) sum) ; => 45 (cl-loop with x = 0 with sum = 0 do (setq sum (+ sum x)) (setq x (1+ x)) while (and (> x 0) (< x 10)) finally return sum) ; => 45 ;;; until (let ((x 0) (sum 0)) ;; sum the numbers 0 to 9 (loop-until (= x 10) (setq sum (+ sum x)) (setq x (1+ x))) sum) ; => 45 (cl-loop with x = 0 with sum = 0 until (= x 10) do (setq sum (+ sum x)) (setq x (1+ x)) finally return sum) ; => 45 ;;; foreach (let ((sum 0)) ;; sum the numbers 1 to 5 (loop-for-each x (list 1 2 3 4 5 6 7 8 9) (setq sum (+ sum x)) (when (= x 5) (loop-break))) sum) ; => 15 (cl-loop with sum = 0 for x in (list 1 2 3 4 5 6 7 8 9) do (setq sum (+ sum x)) when (= x 5) return sum) ; => 15 ;;; for-each-line (バッファ各行についてループする) (with-temp-buffer (insert "foo\nbar\nbaz") (let ((lines nil)) (loop-for-each-line (let ((line-start (progn (beginning-of-line) (point))) (line-end (progn (end-of-line) (point)))) (push (buffer-substring line-start line-end) lines) ;; This line should have no effect. (forward-line 1))) (nreverse lines))) ; => ("foo" "bar" "baz") (with-temp-buffer (cl-loop with lines with line-start with line-end initially (insert "foo\nbar\nbaz") (goto-char (point-min)) do (save-excursion (setq line-start (progn (beginning-of-line) (point))) (setq line-end (progn (end-of-line) (point))) (push (buffer-substring line-start line-end) lines) (forward-line 1)) (forward-line 1) until (eobp) finally return (nreverse lines))) ; => ("foo" "bar" "baz") ;;; for-each-line は it で各行の内容を参照できる (with-temp-buffer (insert "foo\nbar\nbaz") (let ((lines nil)) (loop-for-each-line (push it lines)) (nreverse lines))) ; => ("foo" "bar" "baz")
実行方法
$ wget http://rubikitch.com/f/160825054100.loop.el $ emacs -Q -f package-initialize -l 160825054100.loop.el
本日もお読みいただき、ありがとうございました。参考になれば嬉しいです。