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

ContextLを使ってみよう

| 12:08 | ContextLを使ってみよう - わだばLisperになる を含むブックマーク はてなブックマーク - ContextLを使ってみよう - わだばLisperになる

先日開催されたLisp50で作者のPascal Costanza氏によってデモされたこともあって、ちょっと話題になり気味のContextL。

以前から存在は知っていたのですが、コンテクスト指向とか、アスペクト指向というのがさっぱり理解できなかったので放置していました。

しかし、自分は、最近MOPづいているので、これは試してみた方が良いだろうということでとりあえず触ってだけはみることにしました。

インストールは、(asdf-install:install :contextl)のみでOK。

test/demo3.lispになんとなくの使い方と、本家サイトに論文があるので、それを眺めれば筋の良い人は理解できるんだと思います。

どうやらコンテクストという名のレイヤで階層を分けて、特定のレイヤで呼び出すとそのコンテクストに応じたメソッドが呼び出されるという仕組みのようです。

自分は筋が悪いので、良く分からないながらも適当に思い付いた利用法を書き散らかしてみることにしました。

とりあえず、クラスは定義しないで、メソッドのみを実行して遊んでみています。

(require :contextl)

(in-package :contextl-user)

;; 総称関数(defgenericみたいなもの)
(define-layered-function fib (number))

;; 基本
(define-layered-method fib ((n integer))
  (if (< n 2)
      n
      (+ (fib (1- n))
         (fib (- n 2)))))

;; 型宣言してみる/optimize-speedレイヤ
(deflayer optimize-speed)

(define-layered-method fib
  :in optimize-speed ((n integer))
  (declare (fixnum n))
  (if (< n 2)
      n
      (+ (fib (1- n))
         (fib (- n 2)))))

;; 末尾再帰で実装したもの/tail-recurレイヤ
(deflayer tail-recur)

(define-layered-method fib
  :in tail-recur ((n integer))
  (labels ((*fib (n a1 a2)
             (declare (fixnum n a1 a2))
             (if (< n 2)
                 a1
                 (*fib (1- n) (+ a1 a2) a1))))
    (*fib n 1 0)))

;; 無理矢理まぜてみたもの/mixedレイヤ
(deflayer mixed)

(define-layered-method fib
  :in mixed ((n integer))
  (declare (fixnum n))
  (if (< n 2)
      n
      (+ (with-active-layers (tail-recur)
           (fib (1- n)))
         (with-active-layers (optimize-speed)
           (fib (- n 2))))))

;; 試してみる
(progn
  (time (fib 30))

  (time 
   (with-active-layers (optimize-speed)
     (fib 30)))
  
  (time 
   (with-active-layers (tail-recur)
     (fib 30)))
  
  (time 
   (with-active-layers (mixed)
     (fib 30))))

;; >>>
Evaluation took:
  0.231 seconds of real time
  0.228015 seconds of total run time (0.228015 user, 0.000000 system)
  98.70% CPU
  554,444,019 processor cycles
  365,728 bytes consed
  
Evaluation took: optimize-speed
  0.179 seconds of real time
  0.180011 seconds of total run time (0.180011 user, 0.000000 system)
  100.56% CPU
  430,328,007 processor cycles
  219,808 bytes consed
  
Evaluation took: tail-recur
  0.000 seconds of real time
  0.000000 seconds of total run time (0.000000 user, 0.000000 system)
  100.00% CPU
  8,469 processor cycles
  3,008 bytes consed
  
Evaluation took: mixed
  0.039 seconds of real time
  0.040002 seconds of total run time (0.040002 user, 0.000000 system)
  102.56% CPU
  93,135,816 processor cycles
  0 bytes consed

まだ、レイヤが入れ子になった場合にどのレイヤが有効になるのか等、詳しく分っていませんが、なかなか面白そうです。

とか書いてみたんですが、さらに眺めてみると、fibonacci-test.lispというもっと高度なことをやってるファイルがありました…。