SlideShare a Scribd company logo
1 of 52
Download to read offline
つくってあそぼ
ラムダ計算インタプリタ
2018/10/18 KMC例会講座 @utgwkk
自己紹介
• @utgwkk (うたがわきき)
• 工学部情報学科4回生
• プログラミング言語に関する研究
• Euro Truck Simulator 2
参考
[1] Urzyczyn et al. Lectures on the Curry-Howard
Isomorphism, Studies in Logic and the Foundations of
Mathematics, 149, Elsevier Science
[2] http://www.kb.ecei.tohoku.ac.jp/ sumii/class/
keisanki-software-kougaku-2005/lambda.pdf
[3] http://ttic.uchicago.edu/ pl/classes/CMSC336-
Winter08/lectures/lec4.pdf
おしながき
• 動機
• λ計算について知ろう
• λ計算のインタプリタを実装しよう
動機
• λ計算の見た目はコンパクトでかつ表現力が強い
• しかし実装をしたことがない
• 🔜インタプリタを実装してみよう
• 論文読むのがだるいときに手を動かしてた
この講座の目的
• 「みなさんが普段使っているプログラミング言語(のイン
タプリタ)もこのように実装されている」という実感を持っ
てもらう
• λ計算を実装したときのつまずきポイントを共有する
おしながき
• 動機
• λ計算について知ろう
• λ計算のインタプリタを実装しよう
(型無し)λ計算
• 計算のモデル化のひとつ
• 関数をつくる(抽象)
• 関数を適用する
• これだけでなんとチューリング完全
λ項
• M ::= x ¦ λx.M ¦ M M
• xは変数
• 関数抽象は右結合 λx.λy.M = λx.(λy.M)
• 関数適用は左結合 PQR = (PQ)R
• 適当に括弧を加えてよい
さまざまなλ項
• (λx.x)y
• λx.λy.x
• λx.λy.λz.xz(yz)
束縛変数と自由変数
• 束縛変数
• 関数抽象によって束縛されている変数
• λx.λy.xyz の束縛変数はx,y
• 自由変数
• 束縛変数ではないもの
• λx.λy.xyz の自由変数はz
変数の置換
• M[x:=N]
• 項Mに登場する自由変数xを
• (差し支えない範囲で)項Nに置換する
• 差し支えない範囲ってなに?
変数の置換の例
• x[x:=λy.y] = λy.y
• y[x:=λz.z] = y (x y)
• (x z (y x))[x:=λw.w] = (λw.w) z (y (λw.w))
• λx.x[x:=λy.y] = λx.x
• λy.x[x:=λz.z] = λy.λz.z (x y)
α変換
• λx.M =α λy.M[x:=y]
• 差し支えない範囲で引数の変数名は本質ではない
• λx.x と λy.y を区別する必要はないですよね?
β簡約
• ざっくり言えば関数適用
• (λx.M) N -> M[x:=N]
β簡約を体感する
• def f(x): return x + x
• f(2) = 2 + 2 (= 4)
• // これはあくまで体感です
β簡約
(λx.λy.λz.xz(yz)) (λx.λy.x) (λx.λy.x)
->(λy.λz.(λx.λy.x)z(yz)) (λx.λy.x)
->λz.(λx.λy.x)z((λx.λy.x)z)
->λz.(λy.z)((λx.λy.x)z)
->λz.(λy.z)(λy.z)
->λz.z
正規形
• これ以上β簡約できない項
• 例
• x
• λx.x
• λx.λy.x
おしながき
• 動機
• λ計算について知ろう
• λ計算のインタプリタを実装しよう
仕様
• 入力: λ項の文字列表現
• 出力: β簡約のステップと正規形(のようなもの)
• (じつは必ずしも正規形に簡約されるわけではない)
• (β簡約してみて,項が変化しなかったら停止する)
実装言語
• 言語はOCamlを使う
• そこそこツールチェーンがある
• わたしがよく触っている
• 使いこなせてはいないと思う……
簡約までの流れ
トークン列 (LAMBDA ID DOT ...)
構文木 (Fun (x, ...))
De Bruijn index (Fun ...)
(λx.λy.λz.xz(yz))(λx.λy.x)(λx.λy.x)
λx.x
字句解析
構文解析
De Bruijn indexへ変換
β簡約
実装の流れ
トークン列 (LAMBDA ID DOT ...)
構文木 (Fun (x, ...))
De Bruijn index (Fun ...)
(λx.λy.λz.xz(yz))(λx.λy.x)(λx.λy.x)
λx.x
字句解析
構文解析
De Bruijn indexへ変換
β簡約
(1)
(2)
(3)
(4)
cf. インタプリタ
トークン列 (ID(x) EQ NUM(1) ...)
構文木 (STMT([ASSIGN("x", ...), ...])
仮想機械コード (LOAD 1, STORE 0, ...)
x = 1; x + 1
2
字句解析
構文解析
仮想機械コードへの変換
評価
※どれくらいデータ構造を変換するかは設計による
λ項のデータ型を定義しよう
• M ::= x ¦ λx.M ¦ M M
• 忠実に落としこむ
λ項のデータ型を定義しよう
type id = string



type term =

| Var of id

| Fun of id * term

| App of term * term
実装の流れ
トークン列 (LAMBDA ID DOT ...)
構文木 (Fun (x, ...))
De Bruijn index (Fun ...)
(λx.λy.λz.xz(yz))(λx.λy.x)(λx.λy.x)
λx.x
字句解析
構文解析
De Bruijn indexへ変換
β簡約
(1)
(2)
(3)
(4)
構文解析
• λx.x のような記号列に意味を持たせる作業
• λx.x -> Fun (x, Var x)
• (厳密にはこの記号列をそのまま扱うわけではない)
構文解析器を実装しよう
• menhirを使うよ
• yaccのOCaml版のすごいやつ
• ocamlyaccというのもある
• 文法をBNF風のもので記述
トークンを定義する
• M ::= x ¦ λx.M ¦ M M
• グッと睨んで必要そうなトークンを定義しよう
• ID (変数)
• LAMBDA, DOT (λ, .)
• LPAREN, RPAREN (括弧)
• EOL (λ項の終端)
トークンを定義する
%{

open Syntax

%}



%token <Syntax.id> ID

%token LAMBDA DOT

%token LPAREN RPAREN

%token EOL
文法を定義する
• M ::= x ¦ λx.M ¦ M M
• グッと睨んで文法を書く
• <main> ::= <Expr> EOL
• <Expr> ::= LAMBDA ID DOT <Expr> ¦ <AppExpr>
• <AppExpr> ::= <AppExpr> <AExpr> ¦ <AExpr>
• <AExpr> ::= ID ¦ LPAREN <Expr> RPAREN
文法を定義する
%start main

%type <Syntax.term> main

%%
main:

Expr EOL { $1 }



Expr:

| LAMBDA i=ID DOT e=Expr { Fun (i, e) }

| AppExpr { $1 }



AppExpr:

| e1=AppExpr e2=AExpr { App (e1, e2) }

| AExpr { $1 }



AExpr:

| i=ID { Var i }

| LPAREN e=Expr RPAREN { e }
実装の流れ
トークン列 (LAMBDA ID DOT ...)
構文木 (Fun (x, ...))
De Bruijn index (Fun ...)
(λx.λy.λz.xz(yz))(λx.λy.x)(λx.λy.x)
λx.x
字句解析
構文解析
De Bruijn indexへ変換
β簡約
(1)
(2)
(3)
(4)
字句解析
• そもそもλx.xのような文字列のままだと扱いづらい
• 空白文字を無視するとか
• コメントもここで取り除かれる
• LAMBDA ID(x) DOT ID(x) ぐらいに明確な列だとよい
字句解析器を実装しよう
• ocamllexを使うよ
• lexのOCaml版
• ルールを正規表現で記述
字句解析ルールを定義する
{

open Parser

}



rule main = parse

[' ' 't']+ { main lexbuf }

| ['n'] { EOL }

| ['a'-'z'] { ID (Lexing.lexeme lexbuf) }

| '' { LAMBDA }

| '.' { DOT }

| '(' { LPAREN }

| ')' { RPAREN }

| eof { exit 0 }
実装の流れ
トークン列 (LAMBDA ID DOT ...)
構文木 (Fun (x, ...))
De Bruijn index (Fun ...)
(λx.λy.λz.xz(yz))(λx.λy.x)(λx.λy.x)
λx.x
字句解析
構文解析
De Bruijn indexへ変換
β簡約
(1)
(2)
(3)
(4)
De Bruijn indexに変換しよう
• ……ってなに?
α変換(思い出す)
• 「束縛変数の名前は本質ではない」
• いっぽう構文木には束縛変数の名前がある
• 🔜適切に変数の名前のことを考えないと

簡約結果がめちゃくちゃになる
• 🔜束縛変数の名前に束縛されたくない!!!!
β簡約(まちがい)
(λx.λy.λz.xz(yz)) (λx.λz.x) (λx.λy.x)
->(λy.λz.(λx.λz.x)z(yz)) (λx.λy.x)
->λz.(λx.λz.x)z((λx.λy.x)z)
->λz.(λz.z)((λx.λy.x)z)
->λz.(λz.z)(λy.z)
->λz.λy.z
De Bruijn indexに変換しよう
• 関数抽象による束縛からのネストの深さで変数が一意に
定まる
• ここでは0-indexとする
• λx.λy.x -> λ.λ.1
• λx.λy.λz.xz(yz) -> λ.λ.λ.2 0 (1 0)
• ただし自由変数は放っておく
De Bruijn indexの強み
• 変数の名前を構文木から取り除くことができる
• 簡約の過程でのα変換を考えなくてよい
De Bruijn indexへの変換
• D(Γ, N, x) = N - Γ(x) (Γ(x)が定義されている)
• D(Γ, N, x) = x (Γ(x)が定義されない,自由変数である)
• D(Γ, N, λx.M) = λ.(D(Γ{x:N+1}, N+1, M))
• D(Γ, N, PQ) = (D(Γ, N, P))(D(Γ, N, Q))
• Dmain(M) = D({}, 0, M)
De Bruijn indexへの変換
• 例
• Dmain(λx.λy.x)
• = D({},0,λx.λy.x)
• = λ.(D({x:1},1,λy.x))
• = λ.λ.(D({x:1,y:2},2,x))
• = λ.λ.(2-1) = λ.λ.1
実装の流れ
トークン列 (LAMBDA ID DOT ...)
構文木 (Fun (x, ...))
De Bruijn index (Fun ...)
(λx.λy.λz.xz(yz))(λx.λy.x)(λx.λy.x)
λx.x
字句解析
構文解析
De Bruijn indexへ変換
β簡約
(1)
(2)
(3)
(4)
De Bruijn indexのβ簡約
• 機械的なindexの操作と置換だけでβ簡約が実行される
• (なんかすごい式)
• 資料[3]を参照
実装の流れ
トークン列 (LAMBDA ID DOT ...)
構文木 (Fun (x, ...))
De Bruijn index (Fun ...)
(λx.λy.λz.xz(yz))(λx.λy.x)(λx.λy.x)
λx.x
字句解析
構文解析
De Bruijn indexへ変換
β簡約
(1)
(2)
(3)
(4)
実装したもの
• https://github.com/utgwkk/lambda-chama
デモ
• (x.y.z.xz(yz))(x.y.x)(x.y.x)
• (x.y.z.xz(yz))(x.z.x)(x.y.x) (変数名を変えただけ)
• f.(x.f(xx))(x.f(xx)) (停止しない)
今後の課題
• 型を付ける
• 実装はしたが講座では省略
• 自由変数の扱いをうまくやりたい
まとめ
• λ計算についてなんとなく分かってきた
• λ計算のインタプリタを実装した

More Related Content

What's hot

勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとは勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとは
Takuya Akiba
 
組合せ最適化入門:線形計画から整数計画まで
組合せ最適化入門:線形計画から整数計画まで組合せ最適化入門:線形計画から整数計画まで
組合せ最適化入門:線形計画から整数計画まで
Shunji Umetani
 
『データ解析におけるプライバシー保護』勉強会 秘密計算
『データ解析におけるプライバシー保護』勉強会 秘密計算『データ解析におけるプライバシー保護』勉強会 秘密計算
『データ解析におけるプライバシー保護』勉強会 秘密計算
MITSUNARI Shigeo
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門
Norishige Fukushima
 

What's hot (20)

関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門
 
π計算
π計算π計算
π計算
 
充足可能性問題のいろいろ
充足可能性問題のいろいろ充足可能性問題のいろいろ
充足可能性問題のいろいろ
 
科学技術計算関連Pythonパッケージの概要
科学技術計算関連Pythonパッケージの概要科学技術計算関連Pythonパッケージの概要
科学技術計算関連Pythonパッケージの概要
 
勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとは勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとは
 
AtCoder Beginner Contest 023 解説
AtCoder Beginner Contest 023 解説AtCoder Beginner Contest 023 解説
AtCoder Beginner Contest 023 解説
 
文脈自由文法の話
文脈自由文法の話文脈自由文法の話
文脈自由文法の話
 
組合せ最適化入門:線形計画から整数計画まで
組合せ最適化入門:線形計画から整数計画まで組合せ最適化入門:線形計画から整数計画まで
組合せ最適化入門:線形計画から整数計画まで
 
質問応答システム入門
質問応答システム入門質問応答システム入門
質問応答システム入門
 
たのしい高階関数
たのしい高階関数たのしい高階関数
たのしい高階関数
 
ユークリッド最小全域木
ユークリッド最小全域木ユークリッド最小全域木
ユークリッド最小全域木
 
ctypes拡張モジュール
ctypes拡張モジュールctypes拡張モジュール
ctypes拡張モジュール
 
たのしい関数型
たのしい関数型たのしい関数型
たのしい関数型
 
『データ解析におけるプライバシー保護』勉強会 秘密計算
『データ解析におけるプライバシー保護』勉強会 秘密計算『データ解析におけるプライバシー保護』勉強会 秘密計算
『データ解析におけるプライバシー保護』勉強会 秘密計算
 
組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門組み込み関数(intrinsic)によるSIMD入門
組み込み関数(intrinsic)によるSIMD入門
 
Map
MapMap
Map
 
中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr
 
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~
プログラミングコンテストでのデータ構造 2 ~平衡二分探索木編~
 
Transformerを多層にする際の勾配消失問題と解決法について
Transformerを多層にする際の勾配消失問題と解決法についてTransformerを多層にする際の勾配消失問題と解決法について
Transformerを多層にする際の勾配消失問題と解決法について
 
劣モジュラ最適化と機械学習1章
劣モジュラ最適化と機械学習1章劣モジュラ最適化と機械学習1章
劣モジュラ最適化と機械学習1章
 

Similar to つくってあそぼ ラムダ計算インタプリタ

ROS Tutorial 02 - CIT
ROS Tutorial 02 - CITROS Tutorial 02 - CIT
ROS Tutorial 02 - CIT
Daiki Maekawa
 
Lambda in template_final
Lambda in template_finalLambda in template_final
Lambda in template_final
Cryolite
 
実務者のためのかんたんScalaz
実務者のためのかんたんScalaz実務者のためのかんたんScalaz
実務者のためのかんたんScalaz
Tomoharu ASAMI
 
Inside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfesInside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfes
Takeshi Komiya
 
Jubatusのリアルタイム分散レコメンデーション@TokyoWebmining#17
Jubatusのリアルタイム分散レコメンデーション@TokyoWebmining#17Jubatusのリアルタイム分散レコメンデーション@TokyoWebmining#17
Jubatusのリアルタイム分散レコメンデーション@TokyoWebmining#17
Yuya Unno
 
オブジェクト指向開発におけるObject-Functional Programming
オブジェクト指向開発におけるObject-Functional Programmingオブジェクト指向開発におけるObject-Functional Programming
オブジェクト指向開発におけるObject-Functional Programming
Tomoharu ASAMI
 
Scalaプログラミング・マニアックス
Scalaプログラミング・マニアックスScalaプログラミング・マニアックス
Scalaプログラミング・マニアックス
Tomoharu ASAMI
 
Scalaで萌える関数型プログラミング[1.1.RC1]
Scalaで萌える関数型プログラミング[1.1.RC1]Scalaで萌える関数型プログラミング[1.1.RC1]
Scalaで萌える関数型プログラミング[1.1.RC1]
Ra Zon
 
ぱっと見でわかるC++11
ぱっと見でわかるC++11ぱっと見でわかるC++11
ぱっと見でわかるC++11
えぴ 福田
 

Similar to つくってあそぼ ラムダ計算インタプリタ (20)

Prosym2012
Prosym2012Prosym2012
Prosym2012
 
[第2版]Python機械学習プログラミング 第8章
[第2版]Python機械学習プログラミング 第8章[第2版]Python機械学習プログラミング 第8章
[第2版]Python機械学習プログラミング 第8章
 
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラーNode.jsでつくるNode.js ミニインタープリター&コンパイラー
Node.jsでつくるNode.js ミニインタープリター&コンパイラー
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)
 
ROS Tutorial 02 - CIT
ROS Tutorial 02 - CITROS Tutorial 02 - CIT
ROS Tutorial 02 - CIT
 
Rでreproducible research
Rでreproducible researchRでreproducible research
Rでreproducible research
 
Lambda in template_final
Lambda in template_finalLambda in template_final
Lambda in template_final
 
実務者のためのかんたんScalaz
実務者のためのかんたんScalaz実務者のためのかんたんScalaz
実務者のためのかんたんScalaz
 
Inside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfesInside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfes
 
asm.js x emscripten: The foundation of the next level Web games
asm.js x emscripten: The foundation of the next level Web gamesasm.js x emscripten: The foundation of the next level Web games
asm.js x emscripten: The foundation of the next level Web games
 
C++0x 言語の未来を語る
C++0x 言語の未来を語るC++0x 言語の未来を語る
C++0x 言語の未来を語る
 
Jubatusのリアルタイム分散レコメンデーション@TokyoWebmining#17
Jubatusのリアルタイム分散レコメンデーション@TokyoWebmining#17Jubatusのリアルタイム分散レコメンデーション@TokyoWebmining#17
Jubatusのリアルタイム分散レコメンデーション@TokyoWebmining#17
 
Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標
Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標
Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標
 
オブジェクト指向開発におけるObject-Functional Programming
オブジェクト指向開発におけるObject-Functional Programmingオブジェクト指向開発におけるObject-Functional Programming
オブジェクト指向開発におけるObject-Functional Programming
 
Tokyor23 doradora09
Tokyor23 doradora09Tokyor23 doradora09
Tokyor23 doradora09
 
Scalaプログラミング・マニアックス
Scalaプログラミング・マニアックスScalaプログラミング・マニアックス
Scalaプログラミング・マニアックス
 
Nds meetup8 lt
Nds meetup8 ltNds meetup8 lt
Nds meetup8 lt
 
Scalaで萌える関数型プログラミング[1.1.RC1]
Scalaで萌える関数型プログラミング[1.1.RC1]Scalaで萌える関数型プログラミング[1.1.RC1]
Scalaで萌える関数型プログラミング[1.1.RC1]
 
秀スクリプトの話
秀スクリプトの話秀スクリプトの話
秀スクリプトの話
 
ぱっと見でわかるC++11
ぱっと見でわかるC++11ぱっと見でわかるC++11
ぱっと見でわかるC++11
 

More from 京大 マイコンクラブ

More from 京大 マイコンクラブ (20)

テキストファイルを読む💪 第1回
テキストファイルを読む💪  第1回テキストファイルを読む💪  第1回
テキストファイルを読む💪 第1回
 
かわいくなろうとしたら語彙力が下がった話
かわいくなろうとしたら語彙力が下がった話かわいくなろうとしたら語彙力が下がった話
かわいくなろうとしたら語彙力が下がった話
 
Common Lisp入門
Common Lisp入門Common Lisp入門
Common Lisp入門
 
多倍長整数の乗算と高速フーリエ変換
多倍長整数の乗算と高速フーリエ変換多倍長整数の乗算と高速フーリエ変換
多倍長整数の乗算と高速フーリエ変換
 
Geometry with Unity
Geometry with UnityGeometry with Unity
Geometry with Unity
 
セミコロンレスc++
セミコロンレスc++セミコロンレスc++
セミコロンレスc++
 
エンジニアと健康
エンジニアと健康エンジニアと健康
エンジニアと健康
 
女の子になれなかった人のために
女の子になれなかった人のために女の子になれなかった人のために
女の子になれなかった人のために
 
Pietで競プロしよう
Pietで競プロしようPietで競プロしよう
Pietで競プロしよう
 
もし太陽のコアがIntelCoreだったら
もし太陽のコアがIntelCoreだったらもし太陽のコアがIntelCoreだったら
もし太陽のコアがIntelCoreだったら
 
C# ゲームプログラミングはホントにメモリのことに無頓着でいいの?
C# ゲームプログラミングはホントにメモリのことに無頓着でいいの?C# ゲームプログラミングはホントにメモリのことに無頓着でいいの?
C# ゲームプログラミングはホントにメモリのことに無頓着でいいの?
 
プログラムを高速化する話Ⅱ 〜GPGPU編〜
プログラムを高速化する話Ⅱ 〜GPGPU編〜プログラムを高速化する話Ⅱ 〜GPGPU編〜
プログラムを高速化する話Ⅱ 〜GPGPU編〜
 
ドット絵でプログラミング!難解言語『Piet』勉強会
ドット絵でプログラミング!難解言語『Piet』勉強会ドット絵でプログラミング!難解言語『Piet』勉強会
ドット絵でプログラミング!難解言語『Piet』勉強会
 
No SSH (@nojima; KMC関東例会)
No SSH (@nojima; KMC関東例会)No SSH (@nojima; KMC関東例会)
No SSH (@nojima; KMC関東例会)
 
DTM練習会2017第1.5回 「伴奏の付け方」
DTM練習会2017第1.5回 「伴奏の付け方」DTM練習会2017第1.5回 「伴奏の付け方」
DTM練習会2017第1.5回 「伴奏の付け方」
 
hideya流 テストプレイ観察術
hideya流 テストプレイ観察術hideya流 テストプレイ観察術
hideya流 テストプレイ観察術
 
暗号技術入門 秘密の国のアリス 総集編
暗号技術入門 秘密の国のアリス 総集編暗号技術入門 秘密の国のアリス 総集編
暗号技術入門 秘密の国のアリス 総集編
 
Altseed
AltseedAltseed
Altseed
 
C#でゲームを作る2016 第8回
C#でゲームを作る2016 第8回C#でゲームを作る2016 第8回
C#でゲームを作る2016 第8回
 
C#でゲームを作る2016 第7回
C#でゲームを作る2016 第7回C#でゲームを作る2016 第7回
C#でゲームを作る2016 第7回
 

つくってあそぼ ラムダ計算インタプリタ