Shiika/continuation method(仮)
そういえば記号!が空いている
メソッドの残りの部分を渡すという印にしたらどうだろうか
デメリット
CPS変換が要りそう
Result#try!
code:sk
enum Result<T>
case Ok(value: T)
case Fail(err: Error)
def try!<U>(cont: Fn1<T, U>) -> U
match self
when Ok(value)
cont(value) # Tを渡して継続を実行
when Fail(err)
self # 継続を実行せずエラーをreturn
end
end
end
使用側
def compile(txt: String) -> Result<VmCode>
ast = @parser.parse(txt).try!
@compiler.compile(ast)
end
脱糖後:
def compile(txt: String, cont: Fn1<VmCode, Void>) ->
@parser.parse(txt).try!(fn(value){
ast = value
cont(@compiler.compile(ast))
})
end
def compile(txt: String) ->
@parser.parse(txt).try!(fn(value){
ast = value
@compiler.compile(ast)
})
end
Promise#await!
code:sk
class Promise<T>
def await!<U>(cont: Fn1<T, U>) -> Void
処理がおわったら cont(結果) を呼ぶ
end
end
使用側
def list_books -> Array<String>
res = Http.get(URL).await!
res.get("books")
end
脱糖後:
def list_books(cont: Fn1<Array<String>, Void>)
tmp = Http.get(URL)
tmp.await!(fn(value){
res = value
cont(res.get("books"))
})
end
Object#defer!
code:sk
class Object
def defer!(f: Fn0<Void>, cont: Fn1<Void, Void>)
cont()
f()
end
end
使用側:
def open_file
f = File.open("foo.txt")
defer!{ f.close }
....
end
脱糖後:
def open_file(cont: Fn1<>)
f = File.open("foo.txt")
defer!(fn(){ f.close }, fn(_){
...
})
end
あーわかった。try!とdefer!は後者だけど、await!は前者なんだ
try!, defer!の影響はそのメソッド内で閉じてるけど、await!は呼び出し側も影響をうける
code:sk
def read_file -> String
File.open("foo.txt").read.await!
end
def print_file
s = read_file # ここでブロックすることが期待される
p s
end
解決法は2種類あって
code:sk
def read_file -> Promise<String>
File.open("foo.txt").read.await!
end
def print_file -> Promise<Void>
s = read_file.await!
p s
end
ステートマシンに展開できるんじゃないかな
デメリット:実装が複雑(実装コスト・実行コスト)
メリット:任意のクロージャ内でawait!できる。つまり、ブロックをとるメソッド
Fiberを入れるならありかも
FiberがあればEnumerable#enum_forが作れる
Fiberがなければ?
String#each_lineがIterator的なものを返せばいいのか。
それだとeach_line{}ができない
String#line_streamとか?
2023/04/23
await!だけど型が間違ってて、await!を一度でも使ったら返り値がPromiseで包まれるのが正しいんだわ
code:sk
class Promise<T>
def await!<U>(cont: Fn1<T, U>) -> Promise<T>
処理がおわったら cont(結果) を呼ぶ
end
end
使用側
def list_books -> Promise<Array<String>>
let res = Http.get(URL).await!
res.get("books")
end
脱糖後:
def list_books -> Promise<Array<String>>
Http.get(URL).await!(fn(res){
cont(res.get("books"))
})
end
Result#try!
code:sk
enum Result<T>
case Ok(value: T)
case Fail(err: Error)
def try!<U>(cont: Fn1<T, U>) -> U
match self
when Ok(value)
cont(value) # Tを渡して継続を実行
when Fail(err)
self # 継続を実行せずエラーをreturn
end
end
end
使用側
def compile(txt: String) -> Result<VmCode>
ast = @parser.parse(txt).try!
@compiler.compile(ast)
end
脱糖後:
def compile(txt: String) ->
@parser.parse(txt).try!(fn(value){
ast = value
@compiler.compile(ast)
})
end
Object#defer!
code:sk
class Object
def defer!(f: Fn0<Void>, cont: Fn1<Void, Void>)
cont()
f()
end
end
使用側:
def open_file
f = File.open("foo.txt")
defer!{ f.close }
....
end
脱糖後:
def open_file
f = File.open("foo.txt")
defer!(fn(){ f.close }, fn(_){
...
})
end