私を SKI に連れてって

Post on 08-Feb-2017

257 views 1 download

Transcript of 私を SKI に連れてって

私を SKI に連れてって201x年m月d日 第3回 OUCC LT会 のつもりだったけど長すぎてボツ

お前誰って人のための

すしす

Twitter: @susisu2413

GitHub: susisu

本日の予定

λ計算入門

SKIコンビネータ入門

Lazy K の紹介

λ計算入門

λ計算とは

"計算"を関数とその適用でモデル化したもの

関数型言語の理論的基盤

ここでは型無しλ計算を紹介します

型付きもあるんだよ

λ式

変数 a, b, c, ..., x, y, z, ...

λ抽象 λx.x, λx.λy.(x y), ...

関数適用 (f x)

λ式λx.λy.* は λx y.* と略記する

関数適用の括弧は曖昧でない場合は省略する

x y = (x y)

関数適用は左結合

f x y = ((f x) y)

α-変換

λ抽象の束縛変数名は重要ではない

例えば λx.x = λy.y

束縛変数名を別の名前に置き換える操作をα-変換と呼ぶ

α-変換で同じλ式にできるなら等価

β-簡約

要はただの関数適用の評価

λ抽象内部の束縛変数を全て引数で置き換える

例えば (λx.f x) y = f y

β-簡約で同じλ式にできるなら等価

η-変換どんな引数に対しても同じ結果になるならば、それらは同じといってもいいよね (外延的等価性)

例えば f = λx.f x

これらの間の変換をη-変換と呼ぶ

η-変換で同じλ式にできるなら等価

Quiz

1. λx.x y = λy.y y ?

2. (λx.λx.x y) y = λy.y y ?

3. λx.x = (λx y z.x z (y z)) (λx y.x) (λx y.x) ?

Answer

1. No

2. No

3. Yes

λ計算

λ式と変換・簡約の規則をまとめてλ計算と呼ぶ

λ計算はチューリング完全

どんな手続き (プログラム) もλ式で表現できる

Q. どう計算するの

入力 x が与えられるとする

手続きを表すλ式 p をうまく選べば、例えば y = p x で出力が得られる

y を変換・簡約すれば解読できそう

Q. 数値とかどうするの

数値がなければ、λ式を使えばいいじゃない

真理値がなければ、λ式を使えば

リストがなければ、λ式を

Church数

λ式で自然数を表わすひとつの方法

Church数

0 := λf x.x

1 := λf x.f x

2 := λf x.f (f x)

...

Church数次の自然数を求める関数 Succ

Succ := λn f x.f (n f x)

足し算 Add

Add := λa b f x.a f (b f x)

掛け算はどうなるか考えてみよう

Church数

掛け算 Mul

Mul := λa b f x.a (b f) x

Church数前の自然数を求める関数 Pred

Pred := λn f x. n (λg h.h (g f)) (λy.x) (λy.y)

ただし Pred 0 = 0

キリがないのでこれ以上はやめる

Church真理値

True := λx y.x

False := λx y.y

If := λp x y.p x y = λp.p

Church真理値

AND, OR, NOT

And := λp q.p q False

Or := λp q.p True q

Not := λp.p False True

述語の例

Church数 n が 0 かどうか調べる

0 = λf x.x だった

IsZero := λn. n (λx.False) True

だんだんとプログラムが書ける気がしてきませんか?

Church対

リストや木構造は対 (pair) の連鎖で表現できる

[1, 2, 3] = (1, (2, (3, 空)))

対をλ式で表現できればいいよね

Church対

対をつくる関数 Cons

Cons := λx y c.c x y

かんたん!べんり!

Church対

対の前後を取り出す関数 Car, Cdr

Car := λp.p (λx y.x)

Cdr := λp.p (λx y.y)

Church対

空 (リストの終端) は?

好きなものを使えば良い

False が一般的っぽい?

Quiz入力 x が 2 つのChurch数 a, b のChurch対で与えられる

出力 y = p x が、a = 0 なら y = b、それ以外なら y = a * b となる p を書いてみよう

Succ などこれまでに定義したものは使ってもよい

Answer

例: λx.IsZero (Car x) (Cdr x) (Mul (Car x) (Cdr x))

繰り返し処理

繰り返し処理を関数で表現したい時は、再帰的な関数を書けばいい

f(0) = 1, f(n) = n * f(n - 1)

けれどλ計算では"再帰的な定義"ができないので、単純には書けない

関数の不動点

関数 f に対して、f x = x となる ような x を f の不動点と呼ぶ

Fix関数 f を引数にとり、その不動点を返す関数 Fix が存在したとする

Fix f = f (Fix f)

f = λx n. IsZero n True (x (Pred n))

Fix f n は n 回の空ループになる

Fix

Fix があれば、繰り返し処理を表現することが出来る

このような関数 Fix をなんとかλ式だけで表現できないか?

Fix

できる!

Fix := λf.(λx.f (x x)) (λx.f (x x))

実際に Fix f = f (Fix f) となるか確かめてみるとよいです

λ計算のまとめλ計算は、計算を関数とその適用でモデル化したもの

チューリング完全

数値も真理値もリストもλ式で表現できる

繰り返し処理だってできちゃう

SKIコンビネータ入門

コンビネータ計算とは

!

高階関数 (コンビネータ) を用いて計算を行う

λ計算と同じく、簡約が存在

(P x y z ...) = E

簡約の結果 E は、コンビネータ P の定義による

コンビネータの例

B x y z = x (y z)

C x y z = x z y

W x y = x y y

コンビネータの例

S x y z = x z (y z)

K x y = x

I x = x

実は I = S K K とも書ける

SKIコンビネータ計算

S、K、I の 3 つのコンビネータを、"基底"として用いる

他のコンビネータは S、K、I の組み合わせで表現する

スキーとは関係がない

SKI で何ができるかSKIコンビネータ計算はチューリング完全

λ抽象と相互に変換することができる

SKI→λ は自明

λ→SKI については Wikipedia の「コンビネータ論理」のページを見るとよいかも

SKI でChurch数0 := KI

1 := I

2 := S(S(KS)K)I

...

Succ := S(S(KS)K)

SKI でChurch真理値

True := K

False := KI

If := I

SKI でChurch対

Cons := S(S(KS)(S(KK)(S(KS) (S(K(SI))K))))(KK)

笑っちゃうよね

SKI で Fix (Y)

Fix よりも、不動点コンビネータ Y と呼ぶことが多い (きがする)

Y := SSK(S(K(SS(S(SSK))))K)

Quiz

Church数の掛け算、足し算を SKI で書いてみよう

足し算の方が難しくなるはず

Answer

Mul = S(KS)K

Add = S(KS)(S(K(S(KS))) (S(KK)))

SKI のまとめS, K, I という 3 つのコンビネータと適用だけで計算をする

チューリング完全

λ抽象と相互に変換できる

データも表せるし、繰り返し処理もできる

だんだん自分の SKI 力がどれほどのものか 確かめたくなってきましたよね?

Lazy K

こころ夏目漱石

“精神的に向上心のないものは馬鹿だ”

“精神的に向上心のないものは馬鹿だ”Eager K

Lazy K とは

SKIコンビネータ計算をベースにした言語

遅延評価、故に Lazy

対義語: Eager, Strict

こころの K とは関係がない

遅延評価

結果に必要のない部分を評価 (計算) しないための仕組み

例えば K x y = x の y は必要ないので、評価を省略したい

遅延評価

ほとんどのプログラミング言語では、引数は適用の前に評価される

Lazy K では、引数はそれ自身が関数として適用に使われるまで評価が遅延される (使わなければ評価されない)

これによって、Yコンビネータによる 停止するループや、無限の長さをもつリストが実現できる

入力

入力は文字コードをChurch数で表現したものの、Church対によるリストで与えられる

入力の終端はChurch数 256

256 = SII(SII(S(S(KS)K)I))

ただし"リストの終端"ではない

出力

入力 X とプログラム P に対して、出力は Y = P X

出力も文字コードをChurch数で表現したものの、Church対によるリスト

出力の終端も 256 以上のChurch数

記法

Lazy K には 4 つの記法がある

コンビネータ計算 …… S(KI)I

unlambda …… ``s`kii

Iota …… * と i だけ

Jot …… 0 と 1 だけ

記法 (その他)

空白、改行は無視される

# の後は改行までコメント

空ファイルは I

Lazy K 処理系http://esoteric.sange.fi/essie2/download/lazy-k.zip

Windows 用のバイナリ同梱

GCC でコンパイルするときは lazy.cpp にパッチを当てる

https://gist.github.com/susisu/831e06af2ddee14938c8

Lazy K 処理系

実行はファイルから、または -e で直接プログラムを指定

$ lazy <file>

$ lazy -e <program>

Lazy K 処理系ためしになにか動かしてみる

$ lazy eg/calc.lazy

$ lazy -e SKK

中身を見るともっとたのしい

SKI を組み合わせて、君だけの最強プログラムを作ろう!

Lazy K の闇は深い

参考文献

大体 Wikipedia を読めばいいと思う

ラムダ計算

コンビネータ論理

SKIコンビネータ計算

不動点コンビネータ

参考文献

The Lazy K Programming Language

https://tromp.github.io/cl/lazy-k.html

↑の日本語訳

http://legacy.e.tir.jp/wiliki?%CB%DD%CC%F5%3A%A5%D7%A5%ED%A5%B0%A5%E9%A5%DF%A5%F3%A5%B0%B8%C0%B8%ECLazy_K