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

DylanでSwank

| 23:50 | DylanでSwank - わだばLisperになる を含むブックマーク はてなブックマーク - DylanでSwank - わだばLisperになる

DylanでSWANKサーバ立ててSLIMEからDylanを使うというdswankなるものを発見したので、駄目もとで挑戦の巻

とりあえず、MacOSXで挑戦したのですが、駄目でした。

しょうがないので、Linuxで挑戦したのですが、64bit UbuntuではDylan自体が上手く動かせないので、qemu(kvm)でDebianを起動してビルドしたところ成功しました。

ビルドには、dswank以外に、lisp-readerが必要なようです。

ソースは、404 Not Foundで確認できます。

1. ソースをsvnで引っ張ってくる。

$ svn co svn://anonsvn.gwydiondylan.org/scm/svn/dylan/trunk/fundev/sources/lib/lisp-reader
$ svn co svn://anonsvn.gwydiondylan.org/scm/svn/dylan/trunk/fundev/sources/lib/dswank

2. ビルド

上記二つを同じディレクトリに設置したします。opendylanを適切に起動できるように設定したとして、

$ opendylan -build dswank.hdp
...
Hacker Edition
Version 1.0 [Beta 4]
Copyright (c) 1997-2004, Functional Objects, Inc.
Portions Copyright (c) 2004-2007, Dylan Hackers
All rights reserved.

Project file for missing 'lisp-reader':

となるので、何を指定して良いのか良く分かっていませんが、lisp-readerのファイルを指定

../lisp-reader/lisp-reader.hdp
....
...

ゴリゴリビルドが始まります。30分位ビルドに時間が掛りました。

Linux版の場合、

3. 実行してみる

~/Open-Dylan/bin/dswankにバイナリができるので実行。

起動してはいる様子ですが、外部から接続もできず。どういうことなのかと思い、ソースを眺めてみると、--listenという引数が取れる模様なので、--listenを付けてみると、

$ ~/Open-Dylan/bin/dswank --listen
Waiting for connection on port 4005

となり、

ポート4005番で待機しているようです。

ということで、SLIMEから接続してみます。

M-x slime-connect
127.0.0.1
4005

→接続できました!

まだ、使い方が良く分からないのですが、プロジェクトをオープンしたりビルドコマンドを実行したりはできるようです。

CLのSLIMEと比べてしまうと、かわいそうですが、現状では、ちょっと便利なDylanシェル位の感じです。

とりあえず記念にスクリーンショットを取ってみました。

Ubuntu 7.10の上のqemu上のDebianでdswankを起動して、MacOSXにポートフォワードしてSLIMEと接続という、意味なくややこしい構成になっています。

全然関係ないですが、Dylan用の設定がないか、CVS版のSLIMEを改めて確認してみたら、swank-goo.gooというものを発見しました。GOOでもSWANKが起動できるのか!!

ということで、次はGOOで挑戦します!

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

CLOSで返り値の型チェックはできたりするのか

| 12:20 | CLOSで返り値の型チェックはできたりするのか - わだばLisperになる を含むブックマーク はてなブックマーク - CLOSで返り値の型チェックはできたりするのか - わだばLisperになる

やりたいこと:

Dylanや、GOOのように総称関数で全体の返り値の型を指定してチェックしたい。

考えてみたこと/試してみたこと:

返り値の型をチェックするのに共通のaroundメソッドを定義すれば良いのかなと思い、試してみる。

感想:

一応できてはいるけど…

  1. どっちにしろ動的に基本メソッドを実行した後にチェックするので微妙。
  2. あんまり綺麗に書けてないし、これでは逆にバグの元になりそう。
  3. コンパイラが型の不整合を教えてくれることも期待できないのかも。
  4. defgenericで宣言したい。

マクロにすれば良いんだろうけど、こういう場合の定番の書法があれば、定番書法が知りたい。きっとDylan風にしたい、って人は過去にいた筈。

MOPは良く分からないけど、こういうのはMOPの領域に踏み込む必要があるんだろうか…。

;; あまり役に立っていない微妙なdefgeneric
(defgeneric sequence=>string (arg)
  (:documentation "sequence=>string"))

;; sequenceクラス全般
(defmethod sequence=>string ((arg sequence))
  (format t "sequence -> ~A" arg)
  arg)

;; listに特化 ここでは単に次に特定できるものを呼んでるだけなのであまり意味なし
(defmethod sequence=>string ((arg list))
  (call-next-method))

;; theでstringかどうかをチェック
(defmethod sequence=>string :around ((arg sequence))
  (let ((res (call-next-method)))  ;theに直接全部詰め込むと、難しくて判定できないらしい。
    (the string res)))

;; 実験
(sequence=>string "foo")
>>> sequence -> foo
(sequence=>string '(foo bar baz))
error:>>> The value (FOO BAR BAZ) is not of type STRING.

ゲスト



トラックバック - http://cadr.g.hatena.ne.jp/g000001/20080418