やさしいEmacs-Lisp講座 章末問題1

第10回 低レベル勉強会〜普通のやつらの下を行け〜
 やさしいEmacs-Lisp 講座 読書&実践会 - その4
http://atnd.org/events/9003

に参加することにしたので、

やさしいEmacs-Lisp 講座
http://www.gentei.org/~yuuji/elisp/elisplec.html

を勉強してますが、章末問題1で早速躓いてしまいました。

章末問題1
問 1-1
a-z どのキーを押しても、「僕るねえもんナリよ」が挿入される「るねきちモード」を作りなさい。

(defun insert-runeemon ()
  (interactive)
  (insert "僕るねえもんナリよ\n"))

(defun runekitch-mode ()
  (interactive)
  (setq major-mode 'runekitch-mode
        mode-name "Runekitch Mode")
  (setq runekitch-mode-map (make-keymap))
  (let ((count 97))
    (while (< count 123)
      (eval '(define-key runekitch-mode-map (format "%c" count) 'insert-runeemon))
      (setq count (1+ count))))
  (use-local-map runekitch-mode-map))

で問1-1はたぶんいいんだと思います。

変数countを97から122まででループさせてるのは

?a ; => 97
?z ; => 122

だからです。

問題は問1-2です
問1-2
a-zを押すと、対応するアルファベットで、「僕luneえもんAなりよ」〜「僕luneえもんZなりよ」と、文字列の入るluneえもんモードを作成せよ。

まあ、26個定義書いてもいいんですがDon'tRepeatYourselfの精神で出来ればdefine-keyに引数を渡した関数を設定したいのです。

いろいろ考えたけどだめだったバージョン

(defun insert-luneemon (num)
  (interactive)
  (insert (concat "僕luneえもん" (format "%c" (- count 32)) "ナリよ\n")))

(defun luneemon-mode ()
  (interactive)
  (setq major-mode 'luneemon-mode
        mode-name "Luneemon Mode")
  (setq luneemon-mode-map (make-key-map))

  (let ((count 97))
    (while (< count 123)
      (eval '(define-key luneemon-mode-map (format "%c" count)
               (lambda () (interactive) (insert-luneemon count))))
      (setq count (1+ count))))
  (use-local-map luneemon-mode-map))

これだと、define-keyで定義するときに変数countの値じゃなくてそのまま"(insert-luneemon count)"で定義されるので、どこかでcountが97とかに定義されてれば何をおしても"僕luneえもんAなりよ"しか表示されないのじゃ。

もうちょっとがんばってみます

=========================================================================
やっとでけた。

evalってのは引数にもらったリストをそのまま先頭を関数として解釈して…ってことみたいなので、じゃあ

(define-key lunekitch-mode-map (format "%c" count) 
    (lambda () (interactive) 
               (insert-luneemon 97)))

ってリストをつくってやればいいだけなので完成したのが下

(defun insert-luneemon (count)
  (interactive)
  (insert (concat "僕luneえもん" (format "%c" (- count 32)) "ナリよ\n")))

(defun set-list (c)
  (let ((cmd '(define-key luneemon-mode-map (format "%c" count)))
        (temp-list-1 (cons 'insert-luneemon (cons c())))
        (temp-list-2 '(lambda () (interactive))))
    (setq temp-list-2 (append temp-list-2 (cons temp-list-1 ())))
    (append cmd (cons temp-list-2 ())))))

(defun luneemon-mode ()
  (interactive)
  (setq major-mode 'luneemon-mode
        mode-name "Luneemon Mode")
  (setq luneemon-mode-map (make-keymap))
  (let ((count 97))
    (while (< count 123)
      (eval (set-list count))
      (setq count (1+ count))))
  (use-local-map luneemon-mode-map))

ごり押し感が半端ないですが出来たので良しとします。