Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2008-04-20

CLで学ぶ「プログラミングGauche」 (7)

| 14:39 | CLで学ぶ「プログラミングGauche」 (7) - わだばLisperになる を含むブックマーク はてなブックマーク - CLで学ぶ「プログラミングGauche」 (7) - わだばLisperになる

毎週日曜日にプログラミングGaucheをさらってみることにしました。

今回は、「7章 手続き」です。長いので、セクションごとに分割します。

7.1 手続きオブジェクト

CLは、Schemeとちがって名前空間が1つではありません。

とりあえず、sum-of-numbersを評価すると、sum-of-numbersの変数としての中身が出てきます。

defunで関数を定義するとシンボル(の関数の場所)に関数が登録されるので、シンボルに関連付けられた関数を取り出すには、

(function sum-of-numbers)

;; 略記
#'sum-of-numbers

;; symbol-functionを使った方法
(symbol-function 'sum-of-numbers)

とする必要があります。

こうすると、Gaucheのように

#<FUNCTION SUM-OF-NUMBERS>

のような結果が返って来ます。

CLでの#< 〜 >の定義ですが、#<というのは、読み戻した場合にはエラーにするための構文です。

割と、#< 〜 >の出力を読み戻して使いたいけど、できないんですが…というのはFAQっぽいですが、#<で囲まれているということは、わざわざ読み戻させないように書いているということなので、できない、と考えても良いかもしれません。(ちなみにLispマシンや、SLIMEの会話的操作では可能です。恐らく会話的操作だとできた方が便利だからではないでしょうか。)

別の名前を付ける
(define x sum-of-numbers)

に相当するのは、

(setf (symbol-function 'x) #'sum-of-numbers)

となるかと思います。Schemeと同様にsum-of-numbersが別の内容に定義されてもxは元の定義のままです。ただし、これはシンボルに関連付けられているので、defineと違ってどこで定義しようが大域的になります。ローカルにしたい場合は、letに変数として格納し、funcallを付けて呼び出す等々…になるので、別の名前を付けるという視点ではローカルの場合defineのようにはいかないようです。

無名関数について

CLの場合も同じく無名関数はlambdaで作れます。

ここでdefineについて説明がありますが、defunは関数オブジェクトと名前を関連付ける以外にもドキュメント等色々と関連付けることができ、その他拡張でソースコードの場所を記録したりもします。これはもちろん、1つのシンボルが沢山の情報を属性として分けて格納することができるためです。

無名関数の使われる場面
(defun len (lst)
  (flet ((increment2 (a b)
           (declare (ignore b))
           (1+ a)))
    (reduce #'increment2 lst :initial-value 0)))

;; 無名関数で
(defun len (lst)
  (reduce (lambda (a b) (declare (ignore b))
           (1+ a))
          lst :initial-value 0))

(defun max-number (lst)
  (if (endp lst)
      (error "max-number needs at least one number")
      (reduce (lambda (a b) (if (> a b) a b))
              (cdr lst) :initial-value (car lst))))

(defun print-elements (lst)
  (reduce (lambda (a b) (declare (ignore a)) (print b)) lst
          :initial-value nil))

ここでは無名関数の使われ方が説明されています。CLにはfoldがないので、reduceを使ってみましたが、処理する関数が取る引数の順番が逆なのでややこしいです。srfi-1には、foldのリストが1つだけとれるバージョンのreduceという名前の関数もありますが、これもCLとは逆です。

また、(declare (ignore 〜))が加わっていますが、これはコンパイラに使われない引数を無視するように指示するものです。無くても大丈夫ですが、SBCLだと未使用変数が警告になるので、自分は付けるようにしています。面倒ですがバグが入りにくくなるメリットもあったりはします。