dev.ariel-networks.com

お仕事にまったく
役にたたない内容
のコードレビュー
やりたいと思いま
す。
はじめます。
本日の内容
ちょっと
草植えときますね型言語
Grassコードレビュー
_, ._
( ・ω・) んもー
○={=}〇,
|:::::::::\, ', ´
、、、、、し 、、、(((.@)wvwwWWwvwwWwwvwwwwWWW
wwWwwWWWWWWwwwwWwwvwWWwWwwvwWWW
今回レビューするコード
wWwwwWwwwwwWWWWwvwvwwWWWW
wWWWWwwwvwwWWwwWwwvwwWWWw
WWWwvwWWwWwvwWWwwwwwWwwvw
wWWwWWWwvWwvwwwWWWwwWwwW
WWWwvWwwwWWWWwWWWWwwwWww
WWWWWwWWWWWWwvwwWWwWWWw
vWwwWWwwwwWWWwwwwwwWWWWW
WWWWWwwwwwwwwWwwWWwwwwWW
WwwwwwwvwwwWWWwwWwwWWWWwv
WwwwwwwWWwwwwWWWwwwwWWWW
wWWWWWWWWWWWWWWWWWWWw
wwwwWwwWWwWWWwWWWWwvwWWW
WWWWWWWWWWWWWWWWWWWWW
本日の内容

昔Grassの処理系を実装したので、その経験を
ネタにコードレビューします。

Grassの言語仕様の解説もします。

ラムダ計算とかもさわりだけ解説します。

知らない人向けです。

アリエルには詳しい人がいっぱいいそうなので、
おかしな箇所は突っ込みお願いします。
ちょっと草(略)Grassとは




ID:UenoB作
型無しラムダ計算ベースの関数型言語
形式的定義
使用する文字はwWvの三文字だけ
それ以外の文字は全てコメント扱い。
だから↓こんなのも立派なソースコード
_, ._
(・ω・ )
○={=}〇,
|:::::::::\, ', ´
wvwwWW、、、、、、 し 、、、(((.@)wvwwWWwvwwWwwvw
wwwWWwwWwwWWWWWWwwwwWwwvwWw
ラムダ計算って何?
ググれカス
でも手元にパソコンが無いので
λf x.f x
ラムダ計算のなげやりな概要

アロンゾ・チャーチとスティーヴン・コール・ク
リーネって人が考案

関数の定義と実行を抽象化した計算体系

LispとかHaskellとか関数型言語の基盤理論

要約すると「全てのもの(データも)は関数」

チューリングマシンが「全てのもの(関数も)は
データ」なのでその対極っぽいもの
ラムダ計算の例
■チャーチ数
ZERO := λf x. x
ONE := λf x. f x
TWO := λf x. f (f x)
THREE := λf x. f (f (f x))
#「数」とは関数fを何回xに適用するかと定義
# f = (x + 1), x = 0 でもとの数字に
■チャーチ真理値
TRUE := λx y. x
FALSE := λx y. y
# XとYを受けとって必ずXを返すのがTRUE、
Yを返すのがFALSE
Grassの文法







使う文字はW,w,vだけ。
他はの文字は無視。関数定義より前も無視。
操作は関数定義と関数適用の2つだけ
wから始まるのが関数定義
Wから始まるのが関数適用
関数定義や関数適用はvで区切る
関数適用が連続する場合はvが省略可能
Grassの操作
■関数適用 App(n, m)
・WWwwwみたいなの
・Wの数(n)は関数の位置
・wの数(m)は引数の位置
■関数適用 Abs(n, C)
・wWWWwwWWwwみたいなの
・最初のwの数(n)が引数の数
・その後ろ関数のBodyで0個以上の関数適用
Grassの状態
Grassの状態は(C,E,D)で表わされる



C = コード
E = 環境(スタック)
D = リターン先を記憶
Grassの初期状態(C0,E0,D0)



C0 = 実行しようとするプログラム
E0 = プリミティブ
D0 = (App(1,1)::ε,ε)::(ε,ε)::ε
プリミティブ
E0 = Out :: Succ :: w :: In :: ε
・w
文字"w"(コード119).
関数として使うと自身と引数をeq
・Out
文字を表示する関数.
・In
文字を入力する関数.
・Succ
次の文字を返す関数.ただし255の次は0.
Grassの処理ルール

(App(m, n) :: C, E, D) → (Cm, (Cn, En) :: Em, (C, E) :: D) where E =
(C1, E1) :: (C2, E2) :: … :: (Ci, Ei) :: E' (i = m, n)

(Abs(n, C') :: C, E, D) → (C, (C', E) :: E, D) if n = 1

(Abs(n, C') :: C, E, D) → (C, (Abs(n - 1, C')::ε, E) :: E, D) if n > 1

(ε, f :: E, (C', E') :: D) → (C', f :: E', D)
イミフwww
ルール1:コードの先頭が関数定義で、引数が1つ

処理1:コードの先頭からAbs(1, C')を取り除く

処理2:(C', E) を E にpush
=> クロージャを作成して環境にpush
ルール2:コードの先頭が関数定義で、引数が2つ以上

処理1:コードの先頭からAbs(n, C')を取り除く

処理2:(Abs(n - 1, C')::ε, E)を E にpush
=> 「引数の数を一つ減らした関数定義」をBody
に持つクロージャを作成して環境にpush (カリー化)
ルール3:コードの先頭が関数適用

処理1:コードの先頭からApp(m, n)を取り除く

処理2:Dに(C, E)をpush

処理3:Eの先頭からm番目(Cm, Em)を参照

処理4:CをCmに置き換える

処理5:Eを(Cn, En)::Emに置き換える
=> Dに現在の状態(リターン先)を記録しておく
=> コードを 実行する関数のBody に
環境を 引数::関数定義時の環境 に置き換える
ルール4:コードが空になる

処理1:Dの先頭から(C', E')を取り出す

処理2:CをC'に置き換える

処理3:Eの先頭からfを取り出す

処理4:Eをf::E'に置き換える
=> コードが空になったのでリターン処理をする
# Dの先頭(C',E') は 関数を実行した時の状態
# f は戻り値。戻り先のスタックにpush
れっつり
ーでぃん
ぐ