LISPUSER

LISPMEMOLisp is a programmable programming language. -- John Foderaro

(top)  (memo)  (rss)

Lisp が大人気(ある意味で)

各方面で大絶賛の嵐。というより Lisp を叩くのが人気。

こうして不人気の再生産に入るのか?

追記:1/28 Shiro さんのところに素晴しいエントリが。

  • Lisp:よくある誤解
  • Lisp:よくある正解
  • Lisp:S式の理由

    S式のメリットをLisperに尋ねれば、エディタがどうの、マクロがどうの、といった 回答が真っ先に返って来ると思うんですが、そういう理屈をいくら理解しても S式がダメな人がS式を好きになったりはしません。どうも、もっと根本的な 感覚に大きな隔たりがあるような気がします。非Lisperから理解しがたい、 Lisperの持つ感覚とはどんなものなんでしょうか。Lisp脳から見た世界はどん なものなのでしょうか。

ちょっと前に S 式の利点(エディタがどうの)を説明しようと必死になっていましたがその通りですね。 しかも、このエントリは(マクロがどうの)といった話をしてしまいました :-(

Lisp は不人気。なぜなら Lisp だから

Matz 日記での批判は Lisp のカタログスペック的利点を知った上で指向の違いからきています。 「Lisp である事自体が罪」というようなスタンスなので反論不能です。 orz

そういえば、 Matz 日記 (http://www.rubyist.net/~matz/20061218.html ) にのった記念。なるほど、それで Ruby 方面の人からメールがちらほら来るようになったのか。いろいろツッコミ下さった方々ありがとうございます。

一部誤解もあったので念のため訂正しておきますが、「最高にキモい〜」というのは end の使い方の話です (元ネタ: http://jijixi.azito.com/cgi-bin/diary/index.rb?date=20060328 )。 「Lisper でも Ruby ライクに書くなら end は改行する!! 一行に end を連続させたりしません!!」という主旨だったんですが suck-lisp とか書いたせいで、誤解を生じたようです。

括弧大嫌い

括弧がいばり過ぎ。算数や自然言語などの学習において、 括弧はあくまで補助的役割を果たすものだという思考法が染み着いています。 にもかかわらず、Lispでは括弧に大きな意味があるため、思考のギャップが 生じます。

  1. 括弧色を薄くする
  2. 括弧に意味はありません。括弧によって構築される「構造」に意味があるのです。

    括弧がうざい。人間は多くの場面で結合の優先順位によって楽をすることを 知ってます。Lispはその辺をさっぱりよしなに扱ってくれないので、優しくありません。

  3. プログラムは会話ではなく厳密に書く必要があります。優先順位を「常に意識している/ただしく扱える/間違えない」 パーフェクト超人ならともかく、「なんも考えなくていい」というルーズ な人間には優しい。

    よくある表現が分かりにくい。言語の構成要素がプリミティブ過ぎて、 よくある道具が言語機能になっていないから、ぱっと見で理解できるような書き方をするのに苦労します。 インデントの付け方で工夫できるとは言え、やっぱり辛いです。

よくある表現やよくある道具が欲しいのなら、作ればいいのです!!

(if (= x 0)
  y
  (if (> 1 y)
    (+ x 1)
    (+ x y)))

Lisper にもこれがわかり難いと感じて、かつ cond も嫌いという人はいます。 この世界では高名な Franz の John Foderaro 氏が作成した有名なマクロに if* があります。

(if* (= x 0) then
   y
 elseif (= 1 y) then
   (+ x 1)
 else
   (+ x y))

こんなの。まぁ cond に展開されるんですけどね。ヒマな人は自作してみると 面白いかもしれません。私は http://www.franz.com/~jkf/coding_standards.html を読んで知ったんですけどね。

;; 簡単な仕様
(if a b c) => (if* a then b else c)
 
(if c1 a (if c2 b c))
=> (if c1 then
      a
   elseif c2 then
      b
   else
      c)

正解はこちら → http://www.franz.com/~jkf/ifstar.txt

  • 思い出: 私は最初の挑戦時には奇っ怪なものを作ってしまいまして。丁度授業でやってた状態マシンが使われてて、なるほどーと思ったもんです。

でも if* 使ってるプログラムってほとんど見たことないんだよなぁ…。 大多数の Lisper はやっぱり cond でいいじゃんと思ってしまうのでしょう。

Lisp コードと最適化

なので、C並に速いLispコードは見た目も安全性もC並になる、というのが
私 (Shiro) の経験です。

もっとも、Lispの場合、大量の型宣言はマクロで隠せるのでCよりずいぶん
楽です。また、別のところでも書きましたが、最適化の途中段階ではいく
つものアイディアを実装してベンチマークを取ることが重要ですが、マク
ロを利用することでアルゴリズムの一部をパラメタライズしたバージョン
を簡単に作れるので、より多くのアイディアを試しやすい=結果としてよ
り速いコードに到達できる、ということは言えます。

ここで、「大量の型宣言をマクロで隠せるので楽です」とサラっと書いてありますが ほんとうに小さなマクロで実践できます。手元のコードから実例を探してみました。

;; はじめての版(推定)
(defun magnitude (x y z)
  (+ (* x x) (* y y) (* z z)))
;; 今の版
(defun magnitude (x y z)
  (declare (optimize (speed 3) (safety 0) (debug 0) #+lispworks (float 0)))
  (declare (type single-float x y z))
  (with-type single-float
    (+ (* x x) (* y y) (* z z))))

この with-type マクロですね。出典がどこか忘れましたが、(追記: cllib にあるとの指摘を受けました。どーも。) ちなみにコレの展開結果例は↓こんなかんじ。

[Before]
(with-type single-float
   (+ (* x x) (* y y) (* z z)))
↓
[After]
(the single-float (+ (the single-float (* (the single-float x) (the single-float x)))
                     (the single-float (* (the single-float y) (the single-float y)))
                     (the single-float (* (the single-float z) (the single-float z)))))         

大量の型宣言が。

CL-USER 72 > (disassemble 'magnitude)
239D02DA:
       0:      55               push  ebp
       1:      89E5             move  ebp, esp
       3:      83EC10           sub   esp, 10
       6:      C7042486100000   move  [esp], 1086
      13:      8B7D0C           move  edi, [ebp+C]
      16:      8B5D08           move  ebx, [ebp+8]
      19:      D94701           flds  [edi+1]
      22:      D95DF4           fstps [ebp-C]
      25:      89DF             move  edi, ebx
      27:      D94701           flds  [edi+1]
      30:      D95DF8           fstps [ebp-8]
      33:      D94001           flds  [eax+1]
      36:      D95DFC           fstps [ebp-4]
      39:      D945F4           flds  [ebp-C]
      42:      D84DF4           fmuls [ebp-C]
      45:      D95DF4           fstps [ebp-C]
      48:      D945F8           flds  [ebp-8]
      51:      D84DF8           fmuls [ebp-8]
      54:      D845F4           fadds [ebp-C]
      57:      D95DF4           fstps [ebp-C]
      60:      D945FC           flds  [ebp-4]
      63:      D84DFC           fmuls [ebp-4]
      66:      D845F4           fadds [ebp-C]
      69:      D95DF4           fstps [ebp-C]
      72:      C7450886080000   move  [ebp+8], 886
      79:      D945F4           flds  [ebp-C]
      82:      D95D0C           fstps [ebp+C]
      85:      B501             moveb ch, 1
      87:      C9               leave 
      88:      FF253CDC1220     jmp   [2012DC3C]       ; SYSTEM::RAW-FAST-BOX-SINGLE
NIL

パフォーマンスというと C/C++ 方面の人からツッコミが入りそうなのであらか じめ白状しますが、確かにこれでは C で書くよりは遅いです。実数のストアと ポップを行う FST 系の命令はペアリングできず、並列実行されないという事を 意味します。この場合は人間が書くなら FXCH とかでスタックトップを入れ替 えて演算するでしょう。実際 GCC でも最適化オプションをつけると FXCH を使っ てスタックトップを入れ替えるようなコードを生成します。Lisp コンパイラで も改善されないかなー

posted: 2007/01/25 20:50 | permanent link to this entry | Tags: LISP

(top)  (memo)  (rss)