Kokaの例: State
state effectを定義
koka(ts)effect state<a>
fun get() : a
fun set(x: a) : ()
2つのoperationを定義している
与えられた数値から0まで足し合わす関数を定義
koka(ts)fun sumdown(sum: int = 0): <state<int>,div> int
val i = get()
if i <= 0 then sum else
set(i - 1)
sumdown(sum + i)
val
は定数宣言
内部で get()
/ set()
を使っているので、 state
を持ち、
再帰しているので div
も持つ
この時点では、どこかからgetして、どこかにsetする、と言ってるだけ

実際にその保存先がどこなのかは、 sumdown
は言及しない
interfaceだけ書き、実装は書かれていない
state effect用のhandlerを定義
koka(ts)fun state(init: a, action: () -> <state<a>,div|e> b): <div|e> b
var st := init
with handler
fun get() st
fun set(i) st := i
action()
var
でmutableな変数を宣言
get
はその変数の値を読むだけ、 set
はその変数を更新する
あえてもう少し明示的に書くと
koka(js)fun state(init: a, action: () -> <state<a>,div|e> b): <div|e> b
var st := init
with handler
ctl get()
val f = fn() { st }
resume(f())
ctl set(i)
val f = fn() { st := i }
resume(f())
action()
つまり、 get
も set
も resume
している
呼び出す
sumdown()
という処理を、 state handler
を使って呼び出す
koka(ts)state(10) { sumdown() } // 55
他の例
以下のようにn番目のフィボナッチ数を求める関数を用意する
koka(ts)fun fibonacci(n: int): <state<(int, int)>,div> int
val (a, b): (int, int) = get()
if n <= 1 then a else
set( (b, a + b) )
fibonacci(n - 1)
get()
の返り値部分にtype annotation付けないとerrorになった

関数のeffect typeから推論してくれ〜、と思ったが難しいのか
valに対するannotationの付け方わからなかったけど勘で書いたらいけた

呼び出す
koka(ts)state((0, 1)) { fibonacci(50) } // 7778742049
メモ化してる実装なので普通に速い

参考