!kiyoka.blog.2011_04 RSSPLAIN

Related pages: !kiyoka.blog.list
55555554442222444344443444444444444343444444444444434344444444444444304445555555555555555555555555055555555555555555555055555555555555555555555555555555555550555555555555055555555555555555555555555555555555515555555555555555555555555555555555555555555555555555555555555555555505
5

kiyoka日記。NendoSekkaの開発や、最近思うことなど

5

最新10件!kiyoka.blog   過去記事一覧!kiyoka.blog.list

5

kiyoka.blog_header 

5

このブログを書いている人: 西山 清香(kiyoka) - twitter: @kiyokaEXT

5

5

 

5

 

4

kiyoka.2011_04_30[Nendo][Scheme] let-syntaxの実装方法の検討

4

オレ処理系のNendoについての開発メモ。

4
 SYKjVO
2

 

2

( ※ この記事中のやりかたは全くの間違いだとわかったので、信じないようにお願いします。後日、正しい内容をまとめます )

2

 

2

 

4

let-syntaxの実装方法を検討中。

4

 

4

概要

3

次のような手順でマクロ展開しようと考えている。

4
 ソースコード → 内部表現1  → 内部表現2  → 展開形
4

 

4

 

4

ソースコード → 内部表現1

3

[ソースコード]

4
(define (a-topleve-func arg1 arg2 ...)
4
  (let-syntax ((name1 (syntax-rules ...))
4
               (name2 (syntax-rules ...)))
4
    ... body1 ...
4
    (letrec-syntax ((name1 (syntax-rules ... ))
4
                    (name2 (syntax-rules ... )))
4
      ... body2 ...)))
4

Rubyでマクロ展開する時に少しでも楽をするために、Nendoの初期化スクリプト(init.nnd)でlet-syntaxとletrec-syntaxを両方とも%lexical-define-syntaxを使った内部表現に変換する。

4

let-syntaxとletrec-syntaxの二つは伝統的マクロで以下の形に変換する。

4

let-syntaxのほうだけ、束縛するキーワードの数だけネストさせた形にする。

4

letrec-syntaxのほうは、キーワードが %lexcal-define-syntaxになるだけで、フォームの変形は行わない。

4

 

3

 

4

内部表現1 → 内部表現2

3

[内部表現1]

4
(define (a-toplevel-func arg1 arg2 ...)
4
  (%lexical-define-syntax ((name1 (syntax-rules ...)))
4
      (%lexical-define-syntax ((name2 (syntax-rules ...)))
4
          ... body1 ...
4
          (%lexcal-define-syntax ((name1 (syntax-rules ...))
4
                                  (name2 (syntax-rules ...)))
4
             ... body2 ...))))
4

Rubyで実装したマクロ変換器で、%lexcal-define-syntaxの (syntax-rules ...)部分を実行形式にコンパイルする。

4

実行形式へのコンパイルはNendoのBuilt-in関数であるevalを呼べばいいので、Rubyとinit.nndのどちらでも書ける。

4

(Nendoではsyntax-rules手続きを呼びだせば、LispSyntaxクラスのインスタンスが返ってくる)

4

 

4

変換後は以下のような内部表現になる。(#<LispSyntax>は説明用の便宜上の表現)

4

 

3

 

4

内部表現2 → 展開形

3

[内部表現2]

4
(define (a-toplevel-func arg1 arg2 ...)
4
  (%lexical-syntax ((name1 . #<LispSyntax>))
4
    (%lexical-syntax ((name2 . #<LispSyntax>))
4
       ... body1 ...
4
       (%lexcal-syntax ((name1 . #<LispSyntax>)
4
                        (name2 . #<LispSyntax>))
4
          ... body2 ...))))
4

ここまで来れば簡単だ。

4

Rubyでのマクロ変換器を拡張して、%lexical-syntaxにぶら下がっているキーワードを拾いながら再帰的に body1 や body2 の S式を変換していけばいい。

4

もちろん、レキシカルスコープを持っているので同名のキーワードが出現すれば内側のキーワードでシャドウしながら適用する。

4

 

4

ブログを書いている時点では[内部表現1]→[内部表現2]→[展開形]の部分だけ動いている。(キーワードがちゃんとレキシカルスコープになっているかまではテストできていないが)

4

さて、実際に全体が動くかやってみよう。

4

 

3

 

0

comment (disabled)

4

4

 

4

 

5

kiyoka.2011_04_25[Nendo] Nendo 0.5.0 リリース

5

Nendo 0.5.0をリリースしました。(リリースノート: Nendo.ReleaseNote)

5

rubygems_icon_128

5

リリースの目玉

5

健全なマクロ(hygenic macro)を追加したことです。

5

結果、次の3つをサポートできました。特にutil.listは普段のコーディングで自分でも無いと困るライブラリでした。

5

 

5

srfi-2

5

SRFI-2 AND-LET*: ローカル束縛を伴う AND、条件付き LET* 特殊フォーム

5

 

5

srfi-26

5

SRFI-26 カリー化を伴わないパラメータ特殊化の記法 (cutとcute)

5

 

5

util.list

5

Gaucheのutil.listのサブセットです。Nendoはマルチメソッドディスパッチ機能が無いので、assoc-refの引数指定順序が逆バージョン等は外してあります。

5

take* drop* take-right* drop-right* split-at* slices intersperse cond-list alist->hashtable hash-table->hash-table が使えます。

5

 

5

ただ、サポートできたのはdefine-syntaxのみでレキシカルな構文定義(let-syntaxとletrec-syntax)は未だサポートできていません。

5

 

5

次の目標(let-syntaxとletrec-syntax)

5

これが動けば、util.match が動くのでRubyに強力なパターンマッチが導入できます。

5

NokogiriEXTとutil.matchの組み合わせができると凄いことができるでしょう。

5

 

5

これから挑戦していきます。

5

 

0

comment (disabled)

5

5

 

5

 

5

kiyoka.2011_04_17[Nendo][Scheme] ゆっくり階段を登るがごとく

5

オレ処理系のNendoについての開発メモ。

5
 SYKjVO
5

Gaucheのutil.listが動いた。

5

syntax-rulesも動くようになったし、他にもバグをいくつか修正したので一旦リリースするべきだろう。

5

実は、let-syntaxとletrec-syntaxのようなレキシカルスコープでのみ有効なsyntax定義が実装できていないので、片手落ちなんだけど、リリースした後に取りかかろう。

5

 

5

といっても、実装はそんなに簡単では無さそうだ。

5

恐らく、let-syntaxされたsyntaxだけ先に実行可能コードにコンパイルされ、他の部分は、S式のままの状態を作り出す必要があるのだろう。(関数の一部だけ溶け出したような状態?)

5

マクロ展開用のプロシジャはコンパイルしないと実行できないし、マクロの操作対象はS式でないといけない。うーん、なんか勘違いしていないかな。

5

 

5

過去に「kiyoka.2011_04_06[Nendo][Scheme] syntax-rulesが動いた日」でdefine-syntaxとdefine-rulesが動いた話を書いたが、let-syntaxを実現しようと思ったらだいぶ書き直さないといけないだろう。

5

不完全でもいいので仮実装をして初めて syntactic-closuresEXT で書かれている内容がわかるようになってきた。

5

 

5

凡人はこういう風に、一歩一歩階段を登るしか無いんだろう。

5

今の自分にとっては、好きでやっていれば下手でも一応前進するという実績が大事かも。

5

 

0

comment (disabled)

5

5

 

5

 

5

kiyoka.2011_04_14[Sekka] Sekka 0.8.6 リリース

5

SKKライクな日本語入力メソッド Sekka 0.8.6をリリースしました。(リリースノート Sekka.ReleaseNote)

5
 NbpKsE
5

 

5

version 0.8.6

5
gemの依存規則で、Nendoの依存バージョンとして0.4.1のみとした。
5
 今後、NendoのライブラリAPIの仕様変更で動かなくなる可能性があるため。
5
sekka-server起動時、sekka-serverが使用中のNendoバージョンを表示するようにした。
5

 

5

機能的には、0.8.5から何も変わらないので特にバージョンアップする意味はありません。

5

今後リリースするNendoに下位互換性が無くてもSekkaに影響が無いようにするためです。(実際、一部APIで下位互換性が失われている)

5

 

5

実験したところNendo 0.4.1とNendo 0.5.0の両方がインストールされていても、Sekka 0.8.6はNendo 0.4.1を使うことを確認しました。gemってよくできてるなぁーと思います。

5
~ $ gem list nendo
5
5
*** LOCAL GEMS ***
5
5
nendo (0.5.0, 0.4.1)
5
5
~ $ sekka-server
5
----- Sekka Server Started -----
5
  Sekka version  : 0.8.6
5
  Nendo version  : 0.4.1
5
  dict-db        : /home/kiyoka/.sekka-server/SEKKA-JISYO.SMALL.tch
5
  memcached      : localhost:11211
5
  listenPort     : 12929
5
  proxyHost      : 
5
  proxyPort      : 
5
--------------------------------
5
[2011-04-14 06:14:15] INFO  WEBrick 1.3.1
5
[2011-04-14 06:14:15] INFO  ruby 1.9.2 (2011-02-18) [i686-linux]
5
[2011-04-14 06:14:15] INFO  WEBrick::HTTPServer#start: pid=11284 port=12929
5

 

5

 

0

comment (disabled)

5

5

 

5

 

5

kiyoka.2011_04_10[本] 「言語設計者たちが考えること」の再読

5
 4873114713  言語設計者たちが考えること: Federico Biancuzzi, Shane Warden
5

PealのLarry Wallの章と、RubyのMatzの章を再度読んだ。

5

言語デザインの楽しさを再認識した。有意義でかつ楽しい。お金もかからず、知的好奇心を満たしてくれる最高の遊びだと思う。仕事では役に立たないけど...

5

私のようにSchemeのような仕様が既に決まっている言語の処理系を作るだけでも楽しいが、言語をデザインする作業も楽しいだろうなと想像する。

5

時々は、こういう本を読んで、単ならうScheme処理系の開発というレベルから一段引いて、言語デザインレベルから言語を考えることも必要だなと思う。

5

そのためには、Schemeの仕様に囚われずに、どんな機能が有用かを考える癖も付けていきたい。

5

Haskellとかも本格的に使い込んでHaskellの良い点を理解する時間を取る頃合いかなぁ。

5

 

0

comment (disabled)

5

5

 

5

 

5

kiyoka.2011_04_06[Nendo][Scheme] syntax-rulesが動いた日

5

オレ処理系のNendoについての開発メモ。

5
 SYKjVO
5

chibi-scheme 0.3のer-macro-transformerとsyntax-rulesをそのままNendoに移植を試みていたのだが、ついに成功した。

5

 

5

make-syntactic-closureの実装方法は別段難しくなかった。

5

トップレベルにbindされた変数なら、その識別子をシンボルで返し、そうでなければ(gensym)したシンボルを返せばいいだけだった。

5

Rubyで書いた関数なので、これだけでは意味がわからんだろうけど、雰囲気だけでも伝わるかと思うので、コードを貼っておく。

5
    def _make_MIMARKsyntactic_MIMARKclosure( mac_env, use_env, identifier )
5
      if _pair_QUMARK( identifier )
5
        raise RuntimeError, "Error: make-syntactic-closure requires symbol only..."
5
      else
5
        if mac_env.to_arr.include?( identifier )
5
          identifier
5
        else
5
          sym = toRubySymbol( identifier ) + _gensym( ).to_s
5
          sym.intern
5
        end
5
      end
5
    end
5

 

5

 

5

苦労した主な敗因は、chibi-schemeのsyntax-rulesの定義を自分がよく理解しないままポーティングしようとしていたことだ。

5

こんな複雑な手続きが、一発で動くほど甘い世界ではない。

5

結局、デバッグコード挿入しつつ少しづつ原因を追いこんでいった。

5

 

5

 

5

Nendoにポーティングする時に考慮する必要があったのは以下の点。

5

 

5

... というシンボルをあらかじめグローバルに定義しておく必要があった

5

syntax-rulesを評価する直前に、次のような定義を置いた。

5
(define ... '...)
5

 

1

NendoのScheme非互換仕様に対しての手当が必要だった

5

マクロ展開時 v.1 や v.2 のようなローカル変数を抑制する必要があった。

5

Nendoには instance.method の様な表記をRubyのメソッド呼び出しとして特別扱いしている。

5

(これは、Schemeとは非互換な部分である)

5

 

5

Nendoでは syntax-rulesで展開したコード中の v.1 などの形式が vというインスタンスの1というメソッド呼び出しになってしまう。

5

まあ、数値リテラルのメソッドなんてものは無いので、v.1のような表記は特別に:"v.1"というシンボルとして扱えばいいのだけど、そういう例外も気持ち悪いので特例は入れないつもり。

5

結局 v__1 や v__2 のような変数名を生成するように変更した。

5
 (rename (string->symbol (string-append "v." (number->string count)))))
5

5
 (rename (string->symbol (string-append "v__" (number->string count)))))
5

 

5

chibi-scheme 0.3のany関数にバグがあった。

5

chibi-scheme 0.3のsyntax-rulesの定義中で何回か any が使用されているが、実はchibi-schemeのanyにはバグがある。(これは、chibi-schemeのMLでバグ報告しないといけない)

5

これを見つけるのに苦労したのだよ。

5

次のような場面で使われている。

5
(define-syntax syntax-rules
5
  (er-macro-transformer
5
      .
5
      .
5
             (cond
5
              ((any (lambda (v) (compare t (car v))) vars)
5
               => (lambda (cell)
5
                    (if (<= (cdr cell) dim)
5
                        t
5
                        (error "too few ...'s"))))
5
              (else
5
               (list _rename (list _quote t)))))
5
      .
5
      .
5

anyで見つかったcellを使って、(cdr cell)とかしちゃっているが、これは間違い。

5

本来のanyは条件にマッチした値を返すわけではなく、リスト中に条件を満たすものが1件でもあれば #t を返す。

5

要はchibi-schemeのanyはfindの動作をしちゃっているようだ。

5

 

5

証拠を示そう。

5

SRFI 1: List Libraryのanyの定義EXT

5
    Note the difference between find and any -- find returns the
5
    element that satisfied the predicate; any returns the true value
5
    that the predicate produced.
5
    (any integer? '(a 3 b 2.7))   => #t
5
    (any integer? '(a 3.1 b 2.7)) => #f
5

 

5

とうわけで、このように修正した。

5
 誤り:
5
              ((any (lambda (v) (compare t (car v))) vars)
5
 正解:
5
              ((find (lambda (v) (compare t (car v))) vars)
5

 

5

参考:

5
 $ chibi-scheme
5
> (any even? '(1 2 3 4))
5
2
5
5
 $ gosh
5
gosh> (any even? '(1 2 3 4))
5
#t
5
5
 $ nendo
5
nendo> (any even? '(1 2 3 4))
5
#t
5
nendo> (use srfi-1)
5
20000
5
nendo> (any even? '(1 2 3 4))
5
#t
5

 

5

さて、これでsrfi-2とかGaucheのutil.listがポーティングできるぞー。

5

Nendoでできる世界がさらに広がること間違いナシ。

5

高い壁をひとつ越えた気がする。すごい充実感。

5

 

0

comment (disabled)

5