KokaのEffect Handler
koka(js)fun raise-const() : int
with ctl raise(msg) 42 // ①
8 + safe-divide(1,0) // ②
①で、 raise
というeffectに対するhandlerを書いている
内容は、 raise()
が呼ばれたら常に 42
を返す、というもの
②で、実際に関数を書いている
イメージ的にはJSの try/catch
を逆の順序で書いてる
safe-divide
が以下のような関数である場合
koka(js)fun safe-divide( x : int, y : int ) : raise int
if y==0 then raise("div-by-zero") else x / y
上記の raise-const
を実行すると、
②が実行され、 1 ÷ 0
でraiseが呼ばれる
safe-divide
の中で raise()
が呼ばれる
①のhandler内にジャンプし、 42
を返す
これが raise-const
の最終結果になる
koka(js)fun raise-const()
with ctl raise(msg) resume(42) // ③ resumeして42を返す
8 + safe-divide(1,0) // ④
上記の raise-const
を実行すると、
④が実行され、 1 ÷ 0
でraiseが呼ばれる
safe-divide
の中で raise()
が呼ばれる
③のhandler内にジャンプする
③は 42
を渡して、 safe-divide
の処理を再開する
結果、 safe-divide
の返り値は 42
になり、④で 8+42
が計算され 50
を返す
これが raise-const
の最終結果になる
syntax suger
以下は同じ
koka(js)fun raise-const() : int
with handler
ctl raise(msg) 42
8 + safe-divide(1,0)
koka(js)fun raise-const() : int
with ctl raise(msg) 42
8 + safe-divide(1,0)
文も書ける
koka(js)fun ask-once() : int
var count := 0
with ctl ask()
count := count + 1
if count <= 1 then resume(42) else 0
add-twice()
条件分岐し、resumeするかどうかを決めてる
handleすることで、その関数からeffectが消えるのもポイント
fn
を使うと最適化しやすくなるらしい
ただの糖衣構文ではない
e.g. st, io, console
masking effects
普通にやると
koka(js)effect fun emit( msg : string ) : ()
fun mask-emit()
with fun emit(msg) println("outer:" ++ msg)
with fun emit(msg) println("inner:" ++ msg)
emit("hi")
emit("there")
resultinner:hi
inner:there
当然、内側のhandlerにのみ捕捉される
maskする
koka(js)fun mask-emit()
with fun emit(msg) println("outer:" ++ msg)
with fun emit(msg) println("inner:" ++ msg)
emit("hi")
mask<emit>
emit("there")
最も近いhandlerをmaskすることで、外側のhandlerに捕捉させる
;resultinner:hi
outer:there