読者です 読者をやめる 読者になる 読者になる

Grass再挑戦

ちょっと草植えときますね型言語 Grass
日本語版解説
最初に見たときは面白そうなのにほとんど理解できなくて悲しかったけど、λ計算Lispの基礎をかじった今なら少しは書けそうだ。

で、一昨日ちょっと書いたプリミティブ関数を書き直し。



w (文字関数)

文字"w"(コード119).普通はOutやSuccの引数として使う.関数として呼び出こともできて,引数が同じ文字ならtrue(λx.λy.x),そうでなければfalse(λx.λy.y)を返す.

前回は、CommonLispの名前空間が関数と値で別になってるのをいい事に変数wと関数wを定義したけど、ソースを見るとどうやら全ての文字が関数として扱えなくてはいけないらしい。
日本語にするのが難しいのでまずCommonLispで

(defun charfn (code)
  (lambda (&optional chr)
    (if chr
        (if (= code (funcall chr))
            (lambda (x) (lambda (y) x))
            (lambda (x) (lambda (y) y)))
        code)))

(defvar w
  (charfn (char-code #\w)))

charfnは文字関数にcode(文字コード)を束縛して返す関数。
文字関数は、引数ナシで呼び出すと束縛されてる文字コードを返し、文字関数を引数に与えて呼び出すと、文字コードを比較してtrueかfalseのλ関数を返す。
プリミティブのwはcharfnに"w"の文字コードを渡して返された関数になる。

以下コレにあわせてout,succ,inも書き直し。

Out

文字を表示する関数.引数をそのまま返す.

(defvar out
  (lambda (chr)
    (write-char (code-char (funcall chr)))
    chr))

;wを1個表示 (wWWwwww)
(defun main (self)
  (funcall out w))

渡された文字関数から文字コードを取得してprintするという感じ。

In

文字を入力する関数.入力された文字を返す.EOFなら引数をそのまま返す.

(defvar in
  (lambda (chr)
    (let ((i (read-char)))
      (if i (charfn (char-code i)) chr))))

;入力された文字を表示
(defun main (self)
  (funcall out (funcall in w)))

例をGrassに直す

wWWWWWwwww
WWWw

1: in(スタックの5番目)にw(4番目)を適用し、結果をスタックに積む。
2: 1行目の結果(トップ)をout(3番目)に適用する。

Succ

次の文字を返す関数.ただし255の次は0.

(defvar succ
  (lambda (chr)
    (charfn (mod (1+ (funcall chr)) 256))))

;入力された文字の次の文字を出力
(defun main (self)
  (funcall out
    (funcall succ
      (funcall in w))))

xyzzyのscratchで実行

(main #'main) [Ctrl+J]
a [Return]
b
#<lexical-closure: (anonymous)>

Grassに直す

wWWWWWwwww
WWWWw
WWWWw

1: inにwを適用
2: succに1行目の結果を適用
3: outに2行目の結果を適用



以上が基本。後はλ計算と組み合わせていく。

修正

defun -> defvar に。