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 |

2011-01-16

Gwydion Dylanのインストール (x86 linux)

| 13:45 | Gwydion Dylanのインストール (x86 linux) - わだばLisperになる を含むブックマーク はてなブックマーク - Gwydion Dylanのインストール (x86 linux) - わだばLisperになる

自分にとってDylanはたまに動かしてみる言語なのですが、何ヶ月かぶりにちょっと試してみようと思うと動かないことが多いため導入方法をメモっておくことにしました。

たまにしか動かさない環境は、VirtualBox上に温存してみているので、VirtualBox上のDebian GNU/Linux x86 sidの上に導入します。

注意点

Dylanの実装には色々あるのですが、現在ダウンロードして入手できるのは、Gwydion DylanとOpen Dylanです。

Open Dylanの方が充実していて良いのですが環境によっては、導入に難儀するので、今回は、Gwydion Dylanにします。

ダウンロード
wget http://www.opendylan.org/downloads/binaries/linux/x86/gwydion-dylan-2.4.0-x86-linux-glibc23.tar.gz
設置

落したファイルをものを標準の場所以外に展開すると、

File does not exist: "/usr/local/share/dylan/platforms.descr"
アボートしました

のように怒られるので、/usr/local以下に展開

$ cd /usr/local/
$ sudo tar xvf /tmp/gydion-dylan-2.4.0-x86-linux-glibc23.tar.gz

ライブラリのパスの設定

$ cat /etc/ld.conf.d/gwidion-dylan.conf
/usr/local/lib/dylan/2.4.0/x86-linux-gcc33

$ sudo ldconfig -v
...

動作確認

$ make-dylan-app p01
# p01の中にp01.dylanや、Makefile等一式できる。雛形としてHello, Worldプログラムができる。
$ make
$ ./p01
Hello, World!

2010-05-12

SLIMEとLTDを使ってCLのコードをDylanに変換して表示する

| 19:06 | SLIMEとLTDを使ってCLのコードをDylanに変換して表示する - わだばLisperになる を含むブックマーク はてなブックマーク - SLIMEとLTDを使ってCLのコードをDylanに変換して表示する - わだばLisperになる

まったくもって誰も興味がなさそうなエントリーですが、LTDとSLIMEを組み合わせてみたら面白いかなと思い、組み合わせて遊んでみました。

LTDは、最近翻訳された「実用Common Lisp」の著者であるPeter Norvig氏が作成したCommon LispをDylanに変換するツールです。

SLIME

(defun random-string (&key (length 10) (set :lower-alpha))
  "Returns a random lower-case string."
  (declare (optimize (speed 3)))
  (let ((s (make-string length)))
    (declare (simple-string s))
    (dotimes (i length s)
      (setf (schar s i) (random-char set)))))

のようなCLのコード上でslime-ltdすると

// LtD

define method random-string (#key length = 10, set = #"lower-alpha")
  // Returns a random lower-case string.
  let s :: <simple-string> = make(<string>, size: length, fill: ' ');
  for (i from 0 below length) s[i] := random-char(set); finally s; end for;
end method random-string;

のように別枠のバッファにDylanに変換され表示されるようにします。

クレジットの箇所を読むと、LTDの元になったScott McKay氏の書いたlisp-to-dylan.lispはエディタのバッファを置き換えるというものだったらしいので、なんとなく逆行してしまっている気しますが、表示されたDylanのコードを眺めるのも面白いので、これはこれで良いかなと思います。

変換されたコードでは、きちんとコメントが反映されていたり、マクロは展開されたりします。

動かすのに必要なもの

  1. slime.el
  2. dylan-mode.el

他、ANSI CLで廃止になった記述等がありコンパイルできない箇所がある(SBCL)ので適当に直します。

  1. LTDはCL-USERパッケージを前提にしているので、ltdというパッケージを利用するように変更。
  2. read.lispのrecord-file-positionsの置かれている位置を利用している関数より先に持ってゆく
  3. loopの中で、by 'cddrというのを、by #'cddrに直す
  4. string-char型は廃止なので、characterに変更

SLIME側のコード
;; LtD 
(eval-after-load "slime"
  '(progn
     (defun slime-ltd (times)
       (interactive "p")
       (slime-eval-and-ltd
        `(swank:eval-and-grab-output
          ,(format "(WITH-INPUT-FROM-STRING (IN (PRIN1-TO-STRING '%s))(LTD::LTD-EXP IN *STANDARD-OUTPUT*))" 
                   (slime-defun-at-point)))))
     
     (defun slime-eval-and-ltd (form)
       (slime-eval-async form (slime-rcurry #'slime-show-ltd
                                            (slime-current-package))))
     
     (defun slime-show-ltd (string package)
       (slime-with-popup-buffer ("*SLIME LtD*" package t t)
         (dylan-mode)
         (princ "// LtD")
         (terpri)
         (terpri)
         (princ (first string))
         (goto-char (point-min))))
     
     ;; SUPER-SHIFT-D
     (define-key slime-mode-map
       [(super shift ?d)] 'slime-ltd)))

2009-01-16

S式Dylanの処理系

| 07:32 | S式Dylanの処理系 - わだばLisperになる を含むブックマーク はてなブックマーク - S式Dylanの処理系 - わだばLisperになる

大分前に試していてすっかり書くのを忘れていたのですが、Dylanは当初から仕様はオープンだったということもあり、登場時に各所で実験的に作成されたインタープリタがあります。

代表的なものとして、Thomasがあり、当時のScheme処理系の上で動くものでした。

現在でもソースは入手できるので頑張れば今でも動くとは思うのですが、R3RS位なので自分は良く分からず、上手く動かせないでいました。

というところで放置していたのですが、旧MacOS用にコンパイルされたものが配布されているのを発見したので早速MacOSX上のClassic環境で動かしてみたところ素直に動くので記念エントリです。

から入手できます。

(define-method fib ((n <number>))
  (cond ((< n 2) n)
        (else: (+ (fib (- n 2))
                  (fib (- n 1))))))
(fib 10)
;=> 55

(define-class <foo> (<object>)
  x
 (y init-value: 0 init-keyword: y:))

(define-class <bar> (<foo>)
 (z init-function: (method () 333)))

(bind ((foo (make <foo> y: 8)))
  ((setter x) foo 3)
  (list (x foo) (y foo)))
;=> (3 8)

(z (make <bar>))
;=> 333

という風に書いたり試したりして遊べます。

MacOSXのClassic環境自体絶滅しそうですが、興味のある方は試してみてはいかがでしょうか。

2008-06-17

DylanでL-99 (P11 ランレングス圧縮 その2)

| 16:18 | DylanでL-99 (P11 ランレングス圧縮 その2) - わだばLisperになる を含むブックマーク はてなブックマーク - DylanでL-99 (P11 ランレングス圧縮 その2) - わだばLisperになる

CLのsubseqに相当するものがないか探したのですが見付からず。それらしきものの実装では、copy-sequenceして切り出していたので真似してみました。これで良いのでしょうか…。

また、良く考えると、文字列の圧縮表現は変かなあと思いはじめました(;´Д`)普通にリストにした方が良いかも。

format-out("%=\n",
           #(a:, a:, a:, a:, b:, c:, c:, a:, a:, d:, e:, e:, e:, e:).encode-modified);
//=> #(#(4, #"a"), #"b", #(2, #"c"), #(2, #"a"), #"d", #(4, #"e"))

format-out("%=\n",
           #[a:, a:, a:, a:, b:, c:, c:, a:, a:, d:, e:, e:, e:, e:].encode-modified);
//=> #[#(4, #"a"), #"b", #(2, #"c"), #(2, #"a"), #"d", #(4, #"e")]

format-out("%=\n", "aaaabccaadeeee".encode-modified);
//=> "4a;b;2c;2a;d;4e"

// Code:
define generic single?
    (sequence :: <sequence>)
 => (result :: <boolean>);

define method single?
    (sequence :: <sequence>)
 => (result :: <boolean>)
  ~sequence.empty?
    & copy-sequence(sequence, start: 1).empty?
end method single?;

define generic encode-modified
    (sequence :: <sequence>)
 => (result :: <sequence>);

define method encode-modified
    (sequence :: <list>)
 => (result :: <list>)
  as(<list>, next-method())
end method encode-modified;

define method encode-modified
    (sequence :: <vector>)
 => (result :: <vector>)
  as(<vector>, next-method())
end method encode-modified;

define method encode-modified
    (sequence :: <string>)
 => (result :: <string>)
  join(map(method(x)
               if (x.single?)
                 x
               else
                 format-to-string("%d%s", x.size, x.first) 
               end if
           end,
           sequence.pack1),
       ";")
end method encode-modified;

define method encode-modified
    (sequence :: <sequence>)
 => (result :: <sequence>)
  map(method(x) 
          if (x.single?)
            x.first
          else
            list(x.size, x.first) 
          end if
      end,
      sequence.pack1)
end method encode-modified;

2008-06-12

DylanでL-99 (P10 ランレングス圧縮)

| 17:07 | DylanでL-99 (P10 ランレングス圧縮) - わだばLisperになる を含むブックマーク はてなブックマーク - DylanでL-99 (P10 ランレングス圧縮) - わだばLisperになる

前回定義した、packの補助関数のpack1とjoinを使っています。

Dylanのライブラリの取り込み方と定義方法が良く分からない…。

#(a:, a:, a:, a:, b:, c:, c:, a:, a:, d:, e:, e:, e:, e:).encode
//=> #(#(4, a:), #(1, b:), #(2, c:), #(2, a:), #(1, d:), #(4, e:))

#[a:, a:, a:, a:, b:, c:, c:, a:, a:, d:, e:, e:, e:, e:].encode
//=> #[#(4, a:), #(1, b:), #(2, c:), #(2, a:), #(1, d:), #(4, e:)]

"aaaabccaadeeee".encode
//=> "4a;1b;2c;2a;1d;4e"

// Code:
define generic encode
    (sequence :: <sequence>)
 => (result :: <sequence>);

define method encode
    (sequence :: <list>)
 => (result :: <list>)
  as(<list>,next-method())
end method encode;

define method encode
    (sequence :: <vector>)
 => (result :: <vector>)
  as(<vector>,next-method())
end method encode;

define method encode
    (sequence :: <string>)
 => (result :: <string>)
  join(map(method(x)
               format-to-string("%d%s", x.size, x.first) 
           end,
           sequence.pack1),
       ";")
end method encode;

define method encode
    (sequence :: <sequence>)
 => (result :: <sequence>)
  map(method(x)
          list(x.size, x.first)
      end,
      sequence.pack1)
end method encode;

2008-06-04

DylanでL-99 (P09 連続して現われる要素を纏める)

| 19:25 | DylanでL-99 (P09 連続して現われる要素を纏める) - わだばLisperになる を含むブックマーク はてなブックマーク - DylanでL-99 (P09 連続して現われる要素を纏める) - わだばLisperになる

Perlのjoin的なものがないので、自作してみました。

なんだか無闇に長い…。

#(a:, a:, a:, a:, b:, c:, c:, a:, a:, d:, e:, e:, e:, e:).pack
//=>#(#(#"a", #"a", #"a", #"a"), #(#"b"), #(#"c", #"c"), #(#"a", #"a"), #(#"d"), #(#"e", #"e", #"e", #"e"))
#[a:, a:, a:, a:, b:, c:, c:, a:, a:, d:, e:, e:, e:, e:].pack
//=> #[#(#"a", #"a", #"a", #"a"), #(#"b"), #(#"c", #"c"), #(#"a", #"a"), #(#"d"), #(#"e", #"e", #"e", #"e")]
"aaaabccaadeeee".pack
//=> "aaaa,b,cc,aa,d,eeee"

// Code
module: l99-09

define generic pack
    (sequence :: <sequence>)
 => (result :: <sequence>);

define method pack
    (sequence :: <string>)
 => (result :: <string>)
  if (sequence.empty?)
    sequence
  else
    join(sequence.pack1, ",")
  end if
end method pack;

define method pack
    (sequence :: <sequence>)
 => (result :: <sequence>)
  if (sequence.empty?)
    sequence
  else
    as(select (sequence by instance?)
         <list> => <list>;
         <vector> => <vector>;
       end select, sequence.pack1) 
  end if
end method pack;

define function pack1
    (sequence :: <sequence>)
 => (result :: <sequence>)
  let prev = sequence.first;
  let res = make(<deque>);
  let tem = make(<deque>);
  for (x in sequence)
    unless (x = prev)
      push-last(res, as(<list>, tem));
      tem := make(<deque>);
    end unless;
    push-last(tem, x);
    prev := x;
  end for;
  as(<list>, push-last(res, as(<list>, tem)));
end function pack1;

define generic join 
    (sequence :: <sequence>, delim :: <string>)
 => (result :: <sequence>);

define method join 
    (sequence :: <sequence>, delim :: <string>)
 => (result :: <string>)
  let result = make(<deque>);
  for (c in sequence)
    push-last(result, c);
    push-last(result, delim);
  finally
    result.pop-last;
    apply(concatenate-as, <string>, result);
  end for
end method join;

2008-05-27

DylanでL-99 (P08 連続して現われる要素を圧縮)

| 14:29 | DylanでL-99 (P08 連続して現われる要素を圧縮) - わだばLisperになる を含むブックマーク はてなブックマーク - DylanでL-99 (P08 連続して現われる要素を圧縮) - わだばLisperになる

Dylanにはdequeというコレクションクラスがあり、前後どちらの方向からも追加できるので、それを使って、蓄積して、最後に型変換してみました。

#(a:, a:, a:, a:, b:, c:, a:, a:, d:, e:, e:, e:, e:).compress
//==> #(#"a", #"b", #"c", #"a", #"d", #"e")

#[a:, a:, a:, a:, b:, c:, a:, a:, d:, e:, e:, e:, e:].compress
//==> #[#"a", #"b", #"c", #"a", #"d", #"e"]

"aaaabcaadeeee".compress
//==> "abcade"

// Code
module: l99-08

define generic compress 
    (sequence :: <sequence>)
 => (result :: <sequence>);

define method compress 
    (sequence :: <sequence>)
 => (result :: <sequence>)
  let result = make(<deque>);
  for (elt in sequence)
    if (result.empty? | elt ~= result.last)
      push-last(result, elt)
    end if
  finally
    as(select (sequence by instance?)
         <list> => <list>;
         <string> => <string>;
         <vector> => <vector>;
       end select, result)
  end for
end method compress;

2008-05-21

DylanでL-99 (P07 リストの平坦化)

| 11:48 | DylanでL-99 (P07 リストの平坦化) - わだばLisperになる を含むブックマーク はてなブックマーク - DylanでL-99 (P07 リストの平坦化) - わだばLisperになる

最近の?Dylanはドットで連結できるのですが、これだと見た目は、かなりLispっぽくなくなる気がします。

let seq = #(1, #(2, 3, #(4, 5, #(#(#(6, 7)),8))), 9);
format-out("%= => %=\n",seq, seq.flatten);
//=> #(1, #(2, 3, #(4, 5, #(#(#(6, 7)), 8))), 9)
//  => #(1, 2, 3, 4, 5, 6, 7, 8, 9)

// Code
module: l99-07

define generic flatten
    (sequence :: <sequence>)
 => (result :: <sequence>);

define method flatten
    (sequence :: <list>)
 => (result :: <list>)
  case
    sequence.empty? 
      => sequence;
    instance?(sequence.head, <list>)
      => concatenate(sequence.head.flatten,
                     sequence.tail.flatten);
    otherwise
      => pair(sequence.head,
              sequence.tail.flatten);
  end
end method flatten;

2008-05-13

DylanでL-99 (P06 シーケンスが回文的かを判定)

| 22:00 | DylanでL-99 (P06 シーケンスが回文的かを判定) - わだばLisperになる を含むブックマーク はてなブックマーク - DylanでL-99 (P06 シーケンスが回文的かを判定) - わだばLisperになる

比較の=は、CLでいうequalみたいなもので、==だとeqになる様子。

doは、CLのmapc、Schemeのfor-each。

let lst = #(x:, a:, m:, a:, x:);
let str = "xamax";
let vec = #[x:, a:, m:, a:, x:, a:];

do (method (x) format-out("%= => %=\n", x, x.palindrome?) end,
    list(lst, str, vec));
//>>>
// #(#"x", #"a", #"m", #"a", #"x") => #t
// "xamax" => #t
// #[#"x", #"a", #"m", #"a", #"x", #"a"] => #f

// code
module: l99-06

define generic palindrome? 
    (sequence :: <sequence>)
 => (result :: <boolean>);

define method palindrome?
    (sequence :: <sequence>)
 => (result :: <boolean>)
  (sequence = sequence.reverse)
end method palindrome?;

2008-05-06

DylanでL-99 (P05 シーケンスを反転させる )

| 20:23 | DylanでL-99 (P05 シーケンスを反転させる ) - わだばLisperになる を含むブックマーク はてなブックマーク - DylanでL-99 (P05 シーケンスを反転させる ) - わだばLisperになる

うーん、入力のクラスと同じクラスで出力させたいのだけれど、object-classでは上手く行かないので、selectで振り分け。

絶対変な書き方だと思うんだけれども…。

forは、CLのdoを強化したようなもので、loopの機能も取り入れていますが、基本的に構文はdoに良く似ています。

#(foo:, bar:, baz:).rev
//=> #(baz:, bar:, foo:)

#[foo:, bar:, baz:].rev
//=> #[baz:, bar:, foo:]

"foobarbaz".rev
//=> "zabraboof"

define generic rev 
    (sequence :: <sequence>)
 => (result :: <sequence>);

define method rev
    (sequence :: <sequence>)
 => (result :: <sequence>)
  let result = make(<deque>);
  for (elt in sequence)
    push(result, elt);
  finally 
    as(select (sequence by instance?)
         <list> => <list>;
         <string> => <string>;
         <vector> => <vector>;
       end select, result)
  end for
end method rev;

2008-04-29

DylanでL-99 (P04 リストの長さ)

| 03:31 | DylanでL-99 (P04 リストの長さ) - わだばLisperになる を含むブックマーク はてなブックマーク - DylanでL-99 (P04 リストの長さ) - わだばLisperになる

Dylanでは、シンボルの大文字と小文字を区別しないみたいです。つまりCLと同じ。

ということは、好きに大文字と小文字を混在させて書いたりできるわけですね。

今回reduceを使ってみましたが、引数の順番が決まってるところが違う位でCLのreduceと緒です。

mapや、reduceとなると、無名関数を使いたくなるわけですが、Dylanでは、(lambda() ...)はmethod() ... endと書かれ、クロージャを作るのにもmethodです。

((lambda (x) (+ 3 x)) 97)

は、

method(x)
  3 + x
end(97);

といった感じになるみたいです。

うーん、知れば知るほど中間記法のCLOSという印象は強まります…。

format-out("%d\n", len(#(foo:, bar:, baz:, quux:)));
//=> 4
format-out("%d\n", "foo bar baz".len); // こういう風にも書けるらしい
format-out("%d\n", len("foo bar baz"));
//=> 11

// Code
module: l99-04

define generic LEN
    (sequence :: <sequence>)
 => (result :: <integer>);

define method LEN
    (sequence :: <sequence>)
 => (result :: <integer>)
  reduce(method(res, _) 1 + res end,
         0,
         sequence)
end method LEN;

2008-04-22

DylanでL-99 (P03 K番目の要素)

| 21:40 | DylanでL-99 (P03 K番目の要素) - わだばLisperになる を含むブックマーク はてなブックマーク - DylanでL-99 (P03 K番目の要素) - わだばLisperになる

DylanでCLのcondに相当するものは、caseで、CLのcaseに相当するものは、selectになります。使い勝手も大体同じ。というか、途中からS式からAlgol表記へ乗り換えた経緯もあり、LISP系でお馴染のものは大体あります。CLをAlgol風に表記しても、多分Dylanみたいになるのでしょう…。

自分は、C/Algol系の言語は殆ど書いたことがなくて、S式系の言語ばかりやっているのですが、Algol記法では

  1. セミコロンの使いどころが把握できない。
  2. リストの要素を一々コンマで区切らないといけないのがしんどい、というかコンマを忘れても気付けない。
  3. 括弧で囲まれていると前置記法として読み書きしてしまうので、if (= x y)等がエラーになってもずっと発見できない。
  4. 括弧の使いどころが分からない。(foo 1 2 3)は、foo(1, 2, 3)と書かれるんだと思いますが、foo 1 2 3としてしまう。

という感じで、良くC/Algol系の人がLISPで遭遇する困難と正反対になっている気がしないでもありません。

そして、この辺の問題は気付けないってのが、非常にストレスに感じます。

この辺は、馴れなんじゃないかなと思いますが、自分のように最初からLISPの割合が高い人間が正反対の性質を持つということは、もしかしたら、「どっちににも馴れる」というのは比較的難しいところで、「どっちか」で落着いてしまうところなのかもしれません。

もちろん、ピアノもギターも弾ける人はいる訳で、訓練次第だとは思いますが、多分、楽器の乗換え位しんどい気がします。

element-at(#(a:, b:, c:, d:), 3)
//=> #"c"

;; Code
module: l99-03

define generic element-at 
    (sequence :: <sequence>, position :: <integer>)
 => (result :: false-or(<symbol>));

define method element-at 
    (sequence :: <list>, position :: <integer>)
 => (result :: false-or(<symbol>))
  case 
    empty?(sequence) => #f;
    1 >= position => head(sequence);
    otherwise => element-at(tail(sequence), position - 1);
  end case
end method element-at;

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で挑戦します!

2008-04-16

DylanでL-99 (P02 最後2つの要素)

| 14:42 | DylanでL-99 (P02 最後2つの要素) - わだばLisperになる を含むブックマーク はてなブックマーク - DylanでL-99 (P02 最後2つの要素) - わだばLisperになる

マニュアルを読んでも、あまり書法が理解できないので、参考にできそうなコードを探してみたところ、DylaのCL風ライブラリというものを発見。

作者は、Scott MacKay氏ですが、元Symbolicsの人で、現在ITAに所属しているらしいというLISP街道まっしぐらな方のようです。

Dynamic Languages Wizards Series, Spring 2001にもDavid Moon氏等と一緒にパネリストとして出演してたのを見たことがあります。

とりあえず、真似するのが良いかなと思って、MacKay氏のスタイルを真似。

最初にgenericを作成して、後で特定化されたmethodを追加し、Dylanでは、返り値の型を明示することができるのですが、そこはきっちり書くというスタイルのようです。

let list = #(foo:, bar:, baz:);
format-out("%=\n", last2(list));
// => #(#"bar", #"baz")

let list = #();
format-out("%=\n", last2(list));
// => #()

// Code
module: l99-02

define generic last2
    (sequence :: <sequence>) 
 => (result :: <sequence>);

define method last2
    (sequence :: <list>)
 => (result :: <list>)
  if (2 >= size(sequence))
    sequence
  else
    last2(tail(sequence))
  end if
end method last2;

比較としてCLOSでも考えてみました。

Dylanと違ってdefgenericで返り値の型は指定できないようなので、documentationを付けてるだけです(笑)

返り値の型の指定はどうやったら良いかなと思いましたが、theを付ければ良いだけなんでしょうか。どういうのが定石なんでしょう…。

もしくは、aroundや、afterメソッドで返り値の型をチェックする、なども可能だったりするんでしょうか?

返り値の型を明示するというのは、CLのようにインクリメンタルにコンパイル可能で会話的に開発できる言語でも、割と御利益が多いんじゃないかと思うのですが、どうでしょう。

自分はコンパイラが教えてくれる情報が多くなるので、なんとなく好みです。

(defgeneric last2 (sequence)
  (:documentation "last2"))

(defmethod last2 ((sequence list))
  (if (>= 2 (length sequence))
      (the list sequence)
      (last2 (cdr sequence))))

DylanでL-99 (P01 最後のペアを返す)

| 01:27 | DylanでL-99 (P01 最後のペアを返す) - わだばLisperになる を含むブックマーク はてなブックマーク - DylanでL-99 (P01 最後のペアを返す) - わだばLisperになる

自分は何度かDylanに挑戦してはいるのですが、処理系のインストールの時点で挫折したり、動いてもコンパイルの仕方をすぐ忘れたり、S式でないので文法を憶えられなかったりして何度も挫折しています。

…ということで、L-99なのですが…。

Dylanには複数の処理系があります。Gwydion Dylanと、Open Dylanがあるのですが、今回はOpen Dylanにしておきます。

どうしてかというと、Open Dylanで最近SWANK(SLIMEのバックエンド)が動いてるらしく、SLIMEで開発できるっぽいので、Open Dylanの方が面白そうだということで…。

とりあえず、

http://www.opendylan.org/downloads/opendylan/1.0beta4/

にパッケージがあるので、ダウンロードしてインストールします。

これだけで動くようになりました。

それで、Dylanの開発環境なのですが、この辺も謎なところです。

昔のDylanのスクリーンショット等をみると非常にリッチな開発環境を持っていたようなのですが、フリーでもこういう環境はあるのでしょうか。

とりあえず、追々探って行くことにして、Emacsで書いてコンパイル、という方向で行きます。

Open Dylanの場合、make-dylan-appコマンドがインストールされます。

好きなディレクトリで、例えば、l99-01というプロジェクトの場合、

$ make-dylan-app l99-01

とすると、l99-01というディレクトリが作成され、その中に色々謎なものが生成されます。

それで、ソースファイルは、l99-01.dylanなのですが、これはHello, Woldのテンプレートになっています。

とりあえず、これを編集して、makeファイルも自動生成されるので、ソースを書いたらmakeする、ということになるみたいです。

Dylanでは、

シンボル→foo: もしくは、#"foo"

リスト→#(foo:, bar:, baz)

のようです。

formatのような、format-outがあるんですが、書法は、Cのprintf的です。

headは、carで、tailはcdr

empty?は、空かどうかを判定する総称関数。

コメントは、//で、C++っぽいです。

ちなみに、今回、一番驚いたのは、はてなのシンタックスハイライトにdylanがあったことです(笑)

let list = #(foo:, bar:, baz:);
format-out("%=\n", my-last(list));
// => #(#"baz")

// Code
module: l99-01

define function my-last(list)
  if (empty?(tail(list)))
    list;
  else
    my-last(tail(list));
  end if;
end function my-last;

2008-02-11

S式だった頃のDylan (2)

| 08:53 | S式だった頃のDylan (2) - わだばLisperになる を含むブックマーク はてなブックマーク - S式だった頃のDylan (2) - わだばLisperになる

ちょっと前のエントリでS式Dylanのマニュアルが見付けられない、ということを書きましたが、タイムリーなことに、comp.lang.lispで、同じようにS式Dylanのマニュアルを探してる、という方が、入手できる方法はないかを質問したところ、ほぼ即答で、ウェブからマニュアルを入手できるよ、との回答が!

昔は、AppleのftpでPS版も配布してたらしいんですが、それをHTML化したものでしょうか。

ということで、早速入手!

doが一般化された、forとか面白いです!