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-10-10

ClojureでL-99 (P21 指定した位置に要素を挿入する)

| 06:42 | ClojureでL-99 (P21 指定した位置に要素を挿入する) - わだばLisperになる を含むブックマーク はてなブックマーク - ClojureでL-99 (P21 指定した位置に要素を挿入する) - わだばLisperになる

前回と同じく無限リストを利用してみました。あとおまけで、EmacsのC-tのような操作でくるくるひっくり返してゆくパターンを思い付いたので書いてみました。

とりあえず、condの節の括弧はやっぱりあった方が良いと思うんですよねー。

(defn
  #^{:doc "P21 (*) Insert an element at a given position into a list."
     :test (do (test= (insert-at 'alfa '(a b c d) 2)
                      '(a alfa b c d))
               (test= (insert-at 'alfa [] 2)
                       '(alfa))        
               (test= (insert-at 'alfa '(a b c d) -2)
                      '(alfa a b c d))
               (test= (insert-at 'alfa '(a b c d) 100)
                      '(a b c d alfa))) }
; ---------
  insert-at
; ---------
  ([item coll pos]
     (let [len (count coll)]
       (cond 
        (empty? coll) 
        (list item)
        ;; 
        (>= 0 pos) 
        (cons item coll)
        ;; 
        (<= len pos) 
        (concat coll (list item))
        ;; 
        :else 
        (mapcat #(if (= pos %1) 
                   (list item %2)
                   (list %2))
                (from 1)
                coll)))))

;; 要素をくるくるひっくり返しつつ送ってゆくパターン
(defn insert-at
  ([item coll pos]
     (loop [coll (cons item coll), cnt pos, acc [] ]
       (if (or (>= 1 cnt) (nil? (rest coll)))
         (concat (reverse acc) coll)
         (recur (cons (first coll) (rrest coll))
                (+ -1 cnt)
                (cons (second coll) acc))))))

Flavorsとデザインパターン - Template Method

| 05:18 | Flavorsとデザインパターン - Template Method - わだばLisperになる を含むブックマーク はてなブックマーク - Flavorsとデザインパターン - Template Method - わだばLisperになる

最近Lispマシンのエミュレータを触ってないので、Flavorsでデザインパターンネタはどうかなと思って書いてみました。

とりあえず先日のTemplate Methodです。

Flavorsは、メソッドがクラス属していて、マルチメソッドでもないので、Javaの例を写すにもなんとなくしっくりくる気もします。

CADRエミュレータのFlavorsは最初期のもので、sendの代わりに<-を使用します。

ちなみに、この時期は、<-とfuncallは同じもので、インスタンスをfuncallしてもOKで、(funcall-self 'key)という構文もあり、(<- self 'key)と同じです。

キーワードに一々quoteを付けないといけないのですが、ソースのコメント等では、quoteは無く、この辺が歴史的変遷というか、謎の一つです。

さらにちなむと、Allegro CLには、Flavorsが付いてくるので、AllegroのFlavorsで遊んでみるのも一興かもしれません。

(defflavor abstract () ())

(defmethod (abstract :template-method) (str)
  (<- self ':op2 (<- self ':op1 str)))

(defflavor concrate () (abstract))

(defmethod (concrate :op1) (str)
  (string-upcase str))

(defmethod (concrate :op2) (str)
  (string-reverse str))

(<- (make-instance 'concrate) ':template-method "foo")
;=> OOF

(defflavor concrate2 () (abstract))

(defmethod (concrate2 :op1) (str)
  (string-pluralize str))

(defmethod (concrate2 :op2) (str)
  (string-reverse str))

(<- (make-instance 'concrate2) ':template-method "foo")

;=> soof

CLとデザインパターン - State

| 02:19 | CLとデザインパターン - State - わだばLisperになる を含むブックマーク はてなブックマーク - CLとデザインパターン - State - わだばLisperになる

Template Methodは割とピンとくるものがあったのですが、次はどれにしようかと色々と物色。

どうも、それぞれのパターンの概念が飲込めないので苦戦しています。

とりあえず、Stateパターンは理解できた気がしたので、CLOSで考えてみることに。

Norvig氏によれば、ファーストクラスの型があれば、それで代用可能みたいなことが書いてありましたが、どういうことなんでしょうか。型を変数に格納して渡す?。うーむ。

それで、Stateパターンですが、状態xすることの状態遷移表をそのまま実装したりする簡単になるそうです。確かにそうかもしれません。自分的には、上位のクラスで抽象的な処理を書いて下位のクラスで具体的に実装というところが、前回のTemplate Methodに似ていて、それが束になったような印象もありますが、実際のところはどうなんでしょう。

Greg Sullivan氏の解説では、状況の変更にはchange-classが使えるだろう、とのことだったので、何も考えないで使ってみました。

下の表で言えば、横軸の変化に、change-class、縦の変化には、actionメソッドでの変化ということになるでしょうか。更にactionメソッド内でchange-classを実行すれば、色々変化できそうではあります。

状況
行動挨拶挨拶挨拶
天気についてなし天気について
(defclass foo-state () ())
(defclass asa (foo-state) ())
(defclass hiru (foo-state) ())
(defclass ban (foo-state) ())

(defgeneric action (stat)
  (:documentation "なんらかの行動"))

(defmethod action ((stat foo-state))
  (foo-mesg stat)
  (tenki stat))

(defgeneric foo-mesg (stat)
  (:documentation "挨拶"))

(defmethod foo-mesg ((stat foo-state)))
(defmethod foo-mesg ((stat asa))
  (format 'T "おはよう、おはよう~%"))
(defmethod foo-mesg ((stat hiru))
  (format 'T "こんにちは、こんにちは~%"))
(defmethod foo-mesg ((stat ban))
  (format 'T "こんばんは、こんばんは~%"))

(defgeneric tenki (stat)
  (:documentation "天気について言及"))
(defmethod tenki ((stat foo-state))))
(defmethod tenki ((stat asa))
  (format 'T "良い朝ですね~%"))
(defmethod tenki ((stat ban))
  (format 'T "良い夜ですね~%"))


;; 実験
(let ((stat (make-instance 'hiru)))
  (mapc (lambda (x)
          (change-class stat x) 
          (action stat)
          (format 'T "----~%"))
        '(asa hiru ban)))

;>>>
おはよう、おはよう
良い朝ですね
----
こんにちは、こんにちは
----
こんばんは、こんばんは
良い夜ですね
----