読者です 読者をやめる 読者になる 読者になる

by shigemk2

当面は技術的なことしか書かない

関数のプログラミング

Emacs Lisp
;; 無名関数を変数に代入する
(setq twice (lambda (x) (* x 2)))	; => (lambda (x) (* x 2))
(funcall twice 10)			; => 20

;; 名前付き関数をfuncallで呼ぶ
(+ 3 4)					; => 7
(funcall '+ 3 4)			; => 7
;; 変数にシンボルを指定する例
(setq op '*)
(funcall op 10 10)			; => 100

(apply '+ '(1 2 3))			; => 6
(apply '+ 1 '(2 3))			; => 6
;; 関数の引数リストを変数に格納している場合
(setq args '(2 3 4))			; => (2 3 4)
(apply '+ args)				; => 9
(apply '+ 1 args)			; => 10
;; &rest引数を使う場合
(defun my-plus (&rest args)
  (apply '+ args))
(my-plus 1 2 3 4)			; => 10
;; 各要素に1加える(mapcar使ったほうが遥かに楽)
(let (l)
  (dolist (x '(3 4 5))
  (setq l (cons (1+ x) l)))
  (nreverse l))				; => (4 5 6)
(mapcar '1+ '(3 4 5))			; => (4 5 6)
;; 各要素を10倍する(mapcar使ったほうが(ry
(let (l)
  (dolist (x '(1 2 3))
  (setq l (cons (* x 10) l)))
  (nreverse l))				; => (10 20 30)
(mapcar (lambda (x) (* x 10))
	'(1 2 3))			; => (10 20 30)
;; リスト内要素のうち偶数のみ10倍にする
(delq nil (mapcar (lambda (x)
		    (when (= 0 (% x 2))
		      (* x 10)))
		  '(1 2 3 4 5)))	; => (20 40)

;; 文字列リストをつなげる (マップ関数はidentity)
(mapconcat 'identity '("foo" "bar" "baz") "/") ; => "foo/bar/baz"
(mapconcat 'identity '("foo" "bar" "baz") "")  ; => "foobarbaz"
;; 空文字列がセパレータのときはこちらのほうが楽
(apply 'concat '("foo" "bar" "baz"))	; => "foobarbaz"
;; 文字列以外のリストを繋げる例
(mapconcat 'symbol-name '(foo bar baz) "/") ; => "foo/bar/baz"

;; 1. 関数名を文字列で構成する
;; 2. intern-softで関数名をシンボルにする
;; 3. fboundpでその関数が定義されているかどうか確認する
;; 4. 関数が定義されているとき、funcallで呼び出す

(defun myfunc/foo (x) (* 3 x))
(defun myfunc/bar (x) (+ 5 x))

(defun call-myfunc (name x)
  "myfunc/NAMEを呼ぶ"
  (let ((funcname (intern-soft (format "myfunc/%s" name))))
    (and (fboundp funcname)
	 (funcall funcname x))))
(call-myfunc "foo" 7)			; => 21
(call-myfunc 'bar 5)			; => 10
(call-myfunc 'undefined 10)		; => nil

;; 複数の関数を順次実行
(defun insert-1 (str) (insert "** " str "\n"))
(defun insert-2 (str) (insert "-- " str "\n"))
(with-temp-buffer
  ;; insert-1とinsert-2を呼ぶ
  (let ((funcs '(insert-1 insert-2)))
    (run-hook-with-args 'funcs "Emacs"))
  (buffer-string))			; => "** Emacs\n-- Emacs\n"

;; 成功・失敗するまで関数を連続実行する
(defun make-sexp (str op)
  (list op
	(string-to-number (match-string 1 str))
	(string-to-number (match-string 2 str))))
(defun parse-plus (str)
  (when (string-match "\\([0-9]\\)\\+\\([0-9]\\)" str)
    (make-sexp str '+)))
(defun parse-minus (str)
  (when (string-match "\\([0-9]\\)\\-\\([0-9]\\)" str)
    (make-sexp str '-)))
(setq parsers '(parse-plus parse-minus))
(run-hook-with-args-until-success 'parsers "3+4") ; => (+ 3 4)
(run-hook-with-args-until-success 'parsers "8-6") ; => (- 8 6)

P165

Emacs Lispテクニックバイブル

Emacs Lispテクニックバイブル