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

CLOSでL-99 (P18 範囲切り出し)

| 18:02 | CLOSでL-99 (P18 範囲切り出し) - わだばLisperになる を含むブックマーク はてなブックマーク - CLOSでL-99 (P18 範囲切り出し) - わだばLisperになる

前回までは、CLOSの型でディスパッチする機能にIF式の代わりをさせるという妙なことをしていましたが、大体パターンが分かったのと、これ以降はかなり複雑になるということで、普通にリストだけでなく色んなオブジェクトに対応することでCLOSらしさを出して行くことにしました。しかし、GOOとかDylanと被るんだなあ…。

今回のお題は、範囲の切り出しで、標準の関数だと、subseqがあります。

リストの処理は普通ですが、ベクタは、普通版と、共通部分をaroundメソッドで括り出す書き方をしてみました。

中間処理は、リストを使い、最後に入力の型に合せて型変換する、という流れです。

aroundはこういう使い方もするのかなあ、と手元のソースを調べてみたのですが、こういう風にはあまり書かないようです(笑)

AOP系のソースにはちらっとありましたが、どうなんでしょうねえ。

確かにメソッド結合を濫用していると、あっという間に把握できないコードになるというのは分かる気がします…。

(slice "abcdefghijk" 3 7)
;=> "cdefg"
(slice #(a b c d e f g h i j k) 3 7)
;=> #(c d e f g)
(slice '(a b c d e f g h i j k) 3 7)
;=> (c d e f g)

(defgeneric slice (lst start end)
  (:documentation
   "Given two indices, I and K, the slice is the list containing
the elements between the I'th and K'th element of the
original list (both limits included). Start counting the
elements with 1."))

(defmethod slice ((sequence list) (start integer) (end integer))
  (loop :for idx := 1 :then (1+ idx)
        :for x :in sequence :when (<= start idx end) :collect x))

;; 1 普通に
(defmethod slice ((sequence array) (start integer) (end integer))
  (loop :for idx := 1 :then (1+ idx)
        :for x :across sequence :when (<= start idx end) :collect x :into res
        :finally (return (coerce res (class-of sequence)))))

;; 2 共通部分をaroundメソッドに分割したバージョン
(defmethod slice ((sequence array) (start integer) (end integer))
  (loop :for idx := 1 :then (1+ idx)
        :for x :across sequence :when (<= start idx end) :collect x))

(defmethod slice :around ((sequence sequence) (start integer) (end integer))
  (coerce (call-next-method) (class-of sequence)))