[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
learning lisp別冊: 6点入力が題材
- To: bep@argv.org
- Subject: learning lisp別冊: 6点入力が題材
- From: WATANABE Takayuki <takayuki@la.shonan-it.ac.jp>
- Date: Mon, 04 Jun 2001 20:31:40 +0900 (JST)
- Delivered-To: mailing list bep@argv.org
- Mailing-List: contact bep-help@argv.org; run by ezmlm
渡辺@雑用片付けモードです。
6点入力をキーボードで行うサンプルコードをn高橋さんが書いてくださった後、
実は、高橋さんに、私が書いたコードを添削してもらっていました。Lisp講座の
一環として参考になるかもしれないので、そのときのメールのやり取りを以下に
まとめて書きます。
# もう高橋さんのLisp講座に使われたネタもあるけどね。(笑)
なお、オリジナルの自明な間違いなどは修正してあります。
0) 高橋2渡辺
省略
1) 渡辺2高橋
これでどうですか?
(defun braille-test ()
(let ((i 0) (braille-str) (this-char))
(ding)
(while (< i 100)
(while (not (= ? (setq this-char (read-char))))
(setq braille-str (concat braille-str (char-to-string this-char))))
(insert (format "{%s} " braille-str))
(setq braille-str nil)
(setq i (1+ i)))
(ding)))
2) 高橋2渡辺
文字の比較には = ではなくて char-equal を使った方がお行儀がいい
と言えます。まあ面倒なので私もよく = でやっちゃいますが。
また string の concat は Emacs Lisp にとって比較的重たい操作ですので、
できるだけ回数を減らすようにした方が速度の点で有利です。
それから braille-str はストリングを格納する変数ですから、リセットする
ときは nil よりも "" の方がいいでしょう。変数に型がないのが Lisp のい
いところでもあるんですが、プログラミング作法の点からするとストリング用
の変数にセットする物はストリングで統一した方が better です。
あと、これは好みの問題ですが、
(let ((i 0) (x)) ;; 1
は
(let ((i 0) (x nil)) ;; 2
や
(let ((i 0) x) ;; 3
と等価です。いずれも x は nil で初期化されますが、初期値が nil であるこ
とを明示したいときは 2 を、初期値を気にしない場合は 3 を用いることが多
いようです。1 は文法的には正しいのですが、なぜそう書いたのかがはっきり
しないので避けた方がいいかもしれません。
で、私ならこう書きます。点字入力を10文字分受け付けます。
(defun braille-test ()
(let ((i 0) this-char)
(ding)
(insert "{")
(while (< i 10)
(setq this-char (read-char))
(if (not (char-equal this-char ?\ ))
(insert this-char)
(insert "} {")
(setq i (1+ i))))
(delete-char -2)
(ding)))
ずるいでしょ。:-)
3) 渡辺2高橋
(メールが行方不明??)
4) 高橋2渡辺
> 文字型は整数で表されていても char-equal のほうが良いのですか。
たしかに Emacs では文字を整数で表現していますが、プログラムの可読性を
上げるために文字同士を = で比較するのはやめた方がいいと思います。
case-fold が問題になる可能性がある場合は eq を使うべきかと思います。ち
なみに XEmacs では文字型は数字ではありません(相互変換はできますが)。
>> また string の concat は Emacs Lisp にとって比較的重たい操作ですので、
>> できるだけ回数を減らすようにした方が速度の点で有利です。
> ELispの文字列の長さは固定されているので、毎回新しいセルを作るからですか。
そうです。concat するたびに元のデータを新しい領域にコピーします。私も
あまり詳しいことは知らないのですが、「ストリングの生成は重い」と半田さ
んが言ってました。
> concatに限らず文字列の操作は比較的重たい操作なのでしょうか?
というわけででもないと思います。バッファの中の文字列の比較や操作は効率
的にできるようになっているはずです。何しろエディタですから。
> (let VARLIST BODY...): bind variables according to VARLIST then eval BODY.
> The value of the last form in BODY is returned.
> Each element of VARLIST is a symbol (which is bound to nil)
> or a list (SYMBOL VALUEFORM) (which binds SYMBOL to the value of VALUEFORM).
> All the VALUEFORMs are evalled before any symbols are bound.
> だから、シンボルかリストを書けて、(synbol)としか書かないのはよくなさげ
> ですね。どうしてこれでもOKになるのだろう。
まあ多分歴史的経緯でしょうね。
あともしかしたら (symbol) と (symbol . nil) が等価であるということが関
係しているのかもしれません。
>> で、私ならこう書きます。点字入力を10文字分受け付けます。
>>
>> (defun braille-test ()
>> (let ((i 0) this-char)
>> (ding)
>> (insert "{")
>> (while (< i 10)
>> (setq this-char (read-char))
>> (if (not (char-equal this-char ?\ ))
>> (insert this-char)
>> (insert "} {")
>> (setq i (1+ i))))
>> (delete-char -2)
>> (ding)))
>>
>> ずるいでしょ。:-)
> これの欠点は、最後や中断時に余分な { が残ることですね。
一番最後まで行けば残りませんよ。(delete-char -2) してますから。
また途中で中断されたときの後かたづけをちゃんとやるためには
unwind-protect という関数を使います。
(defun braille-test ()
(let ((i 0) this-char)
(insert "{")
(unwind-protect
(while (< i 10)
(setq this-char (read-char))
(if (not (eq this-char ?\ ))
(insert this-char)
(insert "} {")
(setq i (1+ i))))
(if (eq (preceding-char) ?\{)
(delete-char -2)
(insert "}")))))
> それともともとの目的が同時入力されたキーを取得することだから、
> やはりどこかの変数に納めなければいけないと思います。
> ( 揚げ足取り(^.^) )
> では以下のように文字列の代わりにリストを使うのはどうですか?
すでにバッファ内に入っているのですから、buffer-substring を使って同時
入力されたキーを返せばいいんじゃないでしょうか。
> (defun braille-test ()
> (let ((i 0) (braille-str "") (braille-list nil) this-char)
> (ding)
> (while (< i 10)
> (while (not (char-equal ?\ (setq this-char (read-char))))
> (setq braille-list (cons this-char braille-list)))
> (setq braille-str (mapconcat '(lambda (x) (char-to-string x))
> braille-list ""))
> (insert (format "{%s} " braille-str))
> (setq braille-list nil)
> (setq i (1+ i)))
> (ding)))
文字のリストをストリングに変換するのなら、mapconcat を使う必要はありま
せん。単に (concat braille-list) だけで OK です。
(concat '(?a ?b ?c)) => "abc"
--
渡辺隆行 (WATANABE Takayuki)