Shiika/パターンマッチ その2
まずは必要最低限のものだけ実装する
Foo(a, b, c) およびそのネスト
値として扱われるもの(1, 1.0, true, false)
実装は効率的でなくてよい
単純にif-elseに展開するとか
展開
code:sk
match expr
when 1 then p "one"
when 2 then p "two"
else p "else"
end
# ↓ if-elseに展開
if 1 === expr then p "one"
else
if 2 === expr then p "two"
else p "else" end
end
extractする場合はどうするか
「then節でだけ見えるローカル変数」が必要なので既存の構文に展開できないなあ(ifはスコープを作らないので)
スコープを提供するだけのHirを足すか?
あ、lambda使えばいいのか。
code:sk
match 式 # Maybe<Bar>
when Some(Bar(b))
本体
# ↓
fn(expr: 型){
if expr.class == Some<Bar>
if expr.value.class == Bar
return fn(b: Bar){
return 本体
}(expr.value)
end
end
panic "no match"
}(式)
こうかな。
網羅性チェック
網羅的でないことを許すか?
Rustだとそういうときはif letを使う
2021-09-01
書いてるうちによくわかんなくなってきた。一旦整理が必要
code:sk
match value # Pair<Int, Pair<Bool, String>>
when Pair(i, Pair(b, ""))
body
↓
fn(value: Pair<Int, Pair<Bool, String>>) {
# パターン:Pair(i, _)、値:value
# value.fstをiとする。value.sndを_部分とマッチ
if value.class == Pair<Int, Pair<Bool, String>> # この例だと自明だがMaybeとかの例があるので
fn(i: Int){
# パターン:Pair(b, "")、値:value.snd
# value.snd.fstをbとする。value.snd.sndを""とマッチ
if value.snd.class == Pair<Bool, String>
fn(b: Bool){
if value.snd.snd == ""
return body # TODO: returnだとネストしたfnを脱出できない… letがあればlet+fn(){}でいけるんだが。
end
}(value.snd.fst)
end
}(value.fst)
end
}(value)
スコープを切るだけのHirを追加するのはどうだろうか。
code:sk
match expr # Pair<Int, Pair<Bool, String>>
when Pair(i, Pair(b, ""))
body
↓
# returnで抜けるためにfnでくくる
fn(value: Pair<Int, Pair<Bool, String>>){ # `value'は実際にはgensymした名前にする
scope{ # 具象構文はないが便宜的にこう表記する
# パターン:Pair(i, _)、値:value
# value.fstをiとする。value.sndを_部分とマッチ
if value.class == Pair<Int, Pair<Bool, String>> # この例だと自明だがMaybeとかの例があるので
i = value.fst
# パターン:Pair(b, "")、値:value.snd
# value.snd.fstをbとする。value.snd.sndを""とマッチ
if value.snd.class == Pair<Bool, String>
b = value.snd.fst
if value.snd.snd == ""
return body
end
end
end
}
}(expr)
だいぶましになった。
あ、scope{}とかなくても、型チェック時に見える変数をいじってやれば済むかも
一般に
ひとつのパターン