Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Swift async/await を支えるモナド、継続、コルーチン / iOSDC Japan 2021

Eac0bf787b5279aca5e699ece096956e?s=47 Yasuhiro Inami
September 18, 2021

Swift async/await を支えるモナド、継続、コルーチン / iOSDC Japan 2021

Swift 5.5 async/await を支えるモナド、継続、コルーチン by 稲見 泰宏 | トーク | iOSDC Japan 2021 #iosdc - fortee.jp
https://fortee.jp/iosdc-japan-2021/proposal/9e810800-1829-493b-891f-f80e80bcbdac

Eac0bf787b5279aca5e699ece096956e?s=128

Yasuhiro Inami

September 18, 2021
Tweet

Transcript

  1. Swift async/await Λࢧ͑Δ Ϟφυɺܧଓɺ ίϧʔνϯ 2021/09/18 iOSDC Japan 2021 Yasuhiro

    Inami / @inamiy
  2. None
  3. ඇಉظܭࢉ

  4. ίʔϧόοΫํࣜʹΑΔඇಉظܭࢉ func fetch( request: Request, completion: @escaping (Result<Response, Error>) ->

    Void ) { let task = URLSession.shared .dataTask(with: request) { data, response, error in if let error = error { completion(.failure(error)) } decode(data, completion: { response in completion(.success(response)) }) } task.resume() }
  5. ίʔϧόοΫ஍ࠈ fetch1(request1) { response1 in fetch2(response1) { response2 in fetch3(response2)

    { response3 in fetch4(response3) { response4 in fetch5(response4) { response5 in print(response5) } } } } }
  6. ϦΞΫςΟϒɾϓϩάϥϛϯάʹΑΔඇಉظܭࢉ func fetch(request: Request) -> Observable<Response> { Observable.create { completion

    in let task = URLSession.shared .dataTask(with: request) { data, response, error in if let error = error { completion(.failure(error)) } decode(data, completion: { response in completion(.success(response)) }) } task.resume() return Disposables.create { task.cancel() } } }
  7. qBU.BQʹΑΔϝιουνΣʔϯʢ஍ࠈʁʣ fetch1(request1) .flatMap { response1 in fetch2(response1) } .flatMap {

    response2 in fetch3(response2) } .flatMap { response3 in fetch4(response3) } .flatMap { response4 in fetch5(response4) } .subscribe(onNext: { response5 in print(response5) })
  8. BTZODBXBJUʹΑΔඇಉظܭࢉ func fetch(request: Request) async throws -> Response { let

    (data, _) = try await URLSession.shared.data(with: request) return try JSONDecoder() .decode(Response.self, from: data) } BTZODΩʔϫʔυ BXBJUΩʔϫʔυͰ ඇಉظܭࢉΛ଴ͭ
  9. BTZODBXBJUʹΑΔʮखଓ͖ܕϓϩάϥϛϯάʯ Task.detached { let response1 = try await fetch1(request1) let

    response2 = try await fetch2(response1) let response3 = try await fetch3(response2) let response4 = try await fetch4(response3) let response5 = try await fetch5(response4) print(response5) }
  10. ඇಉظܭࢉ͍Ζ͍Ζ wίʔϧόοΫํࣜ w1SPNJTF'VUVSFɺϦΞΫςΟϒɾϓϩάϥϛϯά w</FX>BTZODBXBJU खଓ͖ ࣮͸ͲΕ΋ಉ͡Α͏ͳ΋ͷͱΈͳͤΔʂ

  11. None
  12. ؔ਺ܕϓϩάϥϛϯά ࡾॐ࢜Λ࿈ΕͯདྷͨΑ

  13. ୯ͳΔࣗݾؔखͷݍʹ͓͚Δ ϞϊΠυର৅ͩΑ ܧଓJTύϫʔ ڠௐతͳൃදΛ໨ࢦͯ͠ ͕Μ͹Γ·͢ Ϟφυ ܧଓ ίϧʔνϯ

  14. ୯ͳΔࣗݾؔखͷݍʹ͓͚Δ ϞϊΠυର৅ͩΑ ܧଓJTύϫʔ ڠௐతͳൃදΛ໨ࢦͯ͠ ͕Μ͹Γ·͢ Ϟφυ ܧଓ ίϧʔνϯ ʲ͓அΓʳ ٙࣅ4XJGUίʔυΛ࢖͍·͢

  15. Ϟφυ Monad ! ju" a monoid in # category of

    endofunctors
  16. J04%$ ݍ࿦ͱ4XJGU΁ͷԠ༻ IUUQTTQFBLFSEFDLDPNJOBNJZJPTEDKBQBO ϓϩάϥϚͷͨΊͷݍ࿦ษڧձ ϓϩάϥϚͷͨΊͷϞφυ ݍ࿦  IUUQTTQFBLFSEFDLDPNJOBNJZOVNCFSDBUQH

  17. Ϟφυ J04%$ΑΓ protocol Monad[M] where Functor[M] { static func unit<C>(_

    c: C) -> M<C> static func join<C>(_ mmc: M<M<C>>) -> M<C> } extension Monad { static func init_() -> M<Void> { .unit(()) } static func flatMap<C, C2>(_ f: C -> M<C2>) -> M<C> -> M<C2> { return { .join(map(f)($0)) } } } 'VODUPS ؔख ͷTVCQSPUPDPM 'VODUPS͸NBQΛ࣋ͭ Ϟφυ͸͞Βʹ VOJUPSJOJU@ KPJOPSqBU.BQ Λ࣋ͭ
  18. Ϟφυͷྫɿ0QUJPOBM enum Optional<T> { case none case some(T) init(_ some:

    T) // unit: T -> Optional<T> func map<U>(_ transform: (T) -> U) -> U? func flatMap<U>(_ transform: (T) -> U?) -> U? } VOJU NBQ qBU.BQΛ࣋ͭͷͰɺ 0QUJPOBM͸Ϟφυ
  19. Ϟφυͷྫɿ"SSBZ struct Array<T> { init() // init_: () -> Array<T>

    func map<U>(_ transform: (T) -> U) -> [U] func flatMap<U>(_ transform: (T) -> [U]) -> [U] } JOJU@ NBQ qBU.BQΛ࣋ͭͷͰɺ "SSBZ͸Ϟφυ
  20. Ϟφυͷྫɿ3Y0CTFSWBCMF struct Observable<T> { // unit: T -> Observable<T> static

    func just(_ element: T) func map<U>(_ transform: (T) -> U) -> Observable<U> func flatMap<U>(_ transform: (T) -> Observable<U>) -> Observable<U> } VOJU NBQ qBU.BQΛ࣋ͭͷͰɺ 0CTFSWBCMF͸Ϟφυ
  21. Ϟφυଇ // ࠨ୯Ґݩ unit(a).flatMap(f) == f(a) // ӈ୯Ґݩ monad.flatMap(unit) ==

    monad // ݁߹཯ monad.flatMap(f).flatMap(g) == monad.flatMap { f($0).flatMap(g) }
  22. Ϟφυଇͷ݁߹཯ // ݁߹཯ monad .flatMap(f) .flatMap(g) == monad.flatMap { f($0).flatMap(g)

    }
  23. Ϟφυଇͷ݁߹཯ // ݁߹཯ͷࠨล monad .flatMap(f) .flatMap(g) .flatMap(h) .flatMap(i) .flatMap(j) //

    ݁߹཯ͷӈล monad.flatMap { f($0).flatMap { g($0).flatMap { h($0).flatMap { i($0).flatMap { j($0) } } } } } ==
  24. Ϟφυ͸ ίʔϧόοΫ஍ࠈΛ ϝιουνΣʔϯʹม׵͢Δ

  25. qBU.BQνΣʔϯͷྫɿ0QUJPOBM$IBJOJOH let monad: Optional<Foo> = … let bar = monad?.is?.just?.a?.monoid

    monad ?.is ?.just ?.a ?.monoid monad .flatMap { $0.is } .flatMap { $0.just } .flatMap { $0.a } .flatMap { $0.monoid } ==
  26. qBU.BQνΣʔϯͷྫɿ0QUJPOBM$IBJOJOH monad ?.is ?.just ?.a ?.monoid monad .flatMap(\.is) .flatMap(\.just) .flatMap(\.a)

    .flatMap(\.monoid) == let monad: Optional<Foo> = … let bar = monad?.is?.just?.a?.monoid 4& ,FZ1BUI&YQSFTTJPOT BT'VODUJPOT
  27. 0QUJPOBM$IBJOJOHͷʮʁʯ͸ qBU.BQ  ,FZ1BUI HFUUFS

  28. qBU.BQνΣʔϯͷྫɿ3FTVMU let monad: Result<Foo, Error> = … let bar =

    monad?.is?.just?.a?.monoid monad .flatMap { $0.is } .flatMap { $0.just } .flatMap { $0.a } .flatMap { $0.monoid } 3FTVMUʹ͸0QUJPOBMͷΑ͏ͳ ઐ༻ͷ౶ҥߏจ͕ͳ͍ 2ϕλʹqBU.BQνΣʔϯ͢Δ Ҏ֎ͷॻ͖ํ͸͋Δ͔ʁ
  29. UISPXTUSZΛ࢖ͬͨखଓ͖ var monad: Foo { get throws { ... }

    } func procedure() throws -> Bar { let monad_ = try monad let is_ = try monad_.is let just_ = try is_.just let a_ = try is_.a let monoid_ = try is_.monoid return monoid_ } 4& &⒎FDUGVM3FBEPOMZ 1SPQFSUJFT 4XJGU "5ISPXJOHGVODUJPOΛ࢖͏ ʢ஫ҙɿΤϥʔܕ෇͚͕ऑ͘ͳΔʣ USZΩʔϫʔυ͕ 0QUJPOBM$IBJOJOHʹ͓͚ΔA Aʹ૬౰
  30. 2ඇಉظܭࢉ΋ಉ͡࿮૊ΈͰ ߟ͑Δ͜ͱ͕Ͱ͖Δʁ ˣ "ͦΕ͕BTZODBXBJU

  31. qBU.BQνΣʔϯͷྫɿ"TZOD let monad: Async<Foo> = … monad .flatMap { $0.is

    } .flatMap { $0.just } .flatMap { $0.a } .flatMap { $0.monoid } "TZODඇಉظϞφυ͕ ͋ΔͱԾఆ͢Δ 1SPNJTF'VUVSF0CTFSWBCMF ͱಉ͡ͱࢥͬͯྑ͍ 2ϕλʹqBU.BQνΣʔϯ͢Δ Ҏ֎ͷॻ͖ํ͸͋Δ͔ʁ
  32. BTZODBXBJUΛ࢖ͬͨखଓ͖ var monad: Foo { get async { ... }

    } func procedure() async -> Bar { let monad_ = await monad let is_ = await monad_.is let just_ = await is_.just let a_ = await is_.a let monoid_ = await is_.monoid return monoid_ } UISPXTUSZΛ BTZODBXBJUΩʔϫʔυʹஔ͖׵͑Δ͚ͩ ""TZODGVODUJPOΛ࢖͏
  33. ͜͜·Ͱͷ·ͱΊʢϞφυʣ wϞφυɿNBQ VOJU qBU.BQ Ϟφυଇ  wϞφυ݁߹཯ɿίʔϧόοΫ஍ࠈΛϝιουνΣʔϯʹม׵ w0QUJPOBMɿqBU.BQ˱A Aԋࢉࢠ w3FTVMUɿqBU.BQ˱USZΩʔϫʔυ

    w"TZODɿqBU.BQ˱BXBJUΩʔϫʔυ ʮϞφυʯͱ ʮݴޠ࢓༷ ʢखଓ͖ͱΩʔϫʔυʣʯ ʹରԠؔ܎͕͋Δʂ
  34. ܭࢉޮՌ Computational Effect

  35. ܭࢉޮՌͱ͸ʁ ܭࢉޮՌʹܭࢉͷաఔͰ௥ՃͰൃੜ͢Δ ෭ ࡞༻  ϞφυʹΑΔܭࢉޮՌ wqBU.BQʢ೚ҙͷܭࢉޮՌʹରͯ͠ڞ௨ͷ໊લʣ  ݴޠ࢓༷ खଓ͖ʷ੍ޚԋࢉࢠʣʹΑΔܭࢉޮՌ

    wA A UISPXTUSZ BTZODBXBJUͳͲ ֤ʑͷܭࢉޮՌʹରͯ͠ҟͳΔ໊લ
  36. ܭࢉޮՌͷྫ wΤϥʔϋϯυϦϯά 3FTVMU UISPXTUSZ  wඇಉظܭࢉ "TZOD1SPNJTF0CTFSWBCMF  BTZODBXBJU 

    wঢ়ଶߋ৽ 4UBUF  wඇܾఆੑܭࢉ "SSBZ ͳͲ
  37. 2Ϟφυͱݴޠ࢓༷ͷ ΪϟοϓΛຒΊΔʹ͸ʁ

  38. EPه๏ do-notation

  39. ࠶ܝɿqBU.BQνΣʔϯͷྫɿ3FTVMU let monad: Result<Foo, Error> = … monad .flatMap {

    $0.is } .flatMap { $0.just } .flatMap { $0.a } .flatMap { $0.monoid }
  40. 3FTVMUͷEPه๏ʹΑΔखଓ͖Խ var monad: Foo { get throws { ... }

    } Result.do { monad_ <- monad is_ <- monad_.is just_ <- is_.just a_ <- just_.a monoid_ <- a_.monoid return monoid_ } 3FTVMU༻ͷEPείʔϓΛ࡞Γɺ AAΛqBU.BQʹݟཱͯɺ ଋറม਺Λࠨଆʹஔ͘ EPه๏qBU.BQνΣʔϯΛ खଓ͖ॲཧʹݟͤΔ౶ҥߏจ
  41. "TZODͷEPه๏ʹΑΔखଓ͖Խ var monad: Foo { get async { ... }

    } Async.do { monad_ <- monad is_ <- monad_.is just_ <- is_.just a_ <- just_.a monoid_ <- a_.monoid return monoid_ } "TZOD༻ͷEPείʔϓΛ࡞Γɺ AAΛqBU.BQʹݟཱͯɺ ଋറม਺Λࠨଆʹஔ͘
  42. Ϟφυ͸ EPه๏ʹΑͬͯ खଓ͖ॲཧʹมܗͰ͖Δ ˣ 2Ϟφυͱݴޠ࢓༷͸ͲͪΒ΋ ʮखଓ͖ʯͱΈͳͤΔͷͰಉ͡ʁ

  43. Ϟφυͷ໰୊఺ɿܭࢉޮՌͷ߹੒ var monad: Foo { get async throws { ...

    } } // try await ͨ͠Γɺtry or await ୯ମݺͼग़͠΋Ͱ͖Δɻ func procedure() async throws -> Bar { let monad_ = try await monad let is_ = await monad_.is let just_ = await is_.just let a_ = try just_.a let monoid_ = await a_.monoid return monoid_ } BTZOD UISPXTͷ߹੒
  44. // Ϟφυ͕ෳ਺ʹωετ͍ͯ͠Δ৔߹ɺ߹੒ܭࢉͷѻ͍͕େม let monad: Async<Result<Foo, Error>> = … // AsyncResult.do

    ͱ͸؆୯ʹॻ͚ͳ͍ͷͰɺͻͱ·ͣ Async.do Λ࢖ͬͯΈΔ Async.do { // `<-` ͸͋͘·Ͱ Async.flatMap ʢResult.flatMap ͸Ͱ͖ͳ͍ʣ monadResult <- monad // ͜ͷdoείʔϓͰ͸Resultͷத਎ΛऔΓग़͢ํ๏͕ͳ͍ͷͰɺ // get()! Ͱڧ੍తʹߦ͏ ʹ ΤϥʔϋϯυϦϯάʹͳ͍ͬͯͳ͍ɻ // ·ͨɺ಺෦Ͱ Result.do Λ࢖ͬͯ΋͏·͍͔͘ͳ͍ɻ let monad_ = monadResult_.get()! is_ <- monad_.is just_ <- is_.just a_ <- just_.a.get()! monoid_ <- a_.monoid return monoid_ } ͜ͷ΍ΓํͰ͸ɺ3FTVMUपΓͷ ΤϥʔϋϯυϦϯά্͕ख͘දݱͰ͖ͳ͍ ˣ Ϟφυ͸ѻ͍ʹ͍͘ʂ
  45. Ϟφυͷ߹੒໰୊ʹର͢Δղܾࡦ͍Ζ͍Ζ wϞφυม׵ࢠ .POBE5SBOTGPSNFS  w5BHMFTT'JOBM wࣗ༝Ϟφυ $PQSPEVDU ؔखͷ௚࿨  w&YUFOTJCMF&GGFDU

    wࣗ༝Ϟφυ 0QFO6OJPO w$PZPOFEB ༨ถా  ࣗ༝Ϟφυ 0QFO6OJPO
  46. ࣗ༝Ϟφυ 'SFF.POBE // ࣗ༝Ϟφυɿunit ͱ join ͕࠶ؼతσʔλߏ଄಺ʹఆٛ͞Ε͍ͯΔ indirect enum Free<F,

    A> { case unit(A) case join(F<Free<F, A>>) } extension Monad[Free<F, _>] where Functor[F] { func flatMap<B>(_ f: A -> Free<F, B>) -> Free<F, B> { switch self { case let .unit(a): return f(a) case let .join(x): return .join(x.map { $0.flatMap(f) }) } } } ؔख'Λ༩͑Δͱɺͦͷߏ଄ʹରԠͨ͠ ΠΠײ͡ͷϞφυ͕खʹೖΔ
  47. // try & await ੍ޚԋࢉࢠΛߏ੒͢Δϕʔεؔख // NOTE: `Value -> Next`

    ͕ίʔϧόοΫʹ૬౰ enum AsyncThrowsF<Next> { // NOTE: <Value> ͸ case಺δΣωϦΫεʢٙࣅSwiftʣ case try_<Value>(Result<Value, Error>, Value -> Next) case await_<Value>(Async<Value>, Value -> Next) } // async + throws ͷ྆ํʹରԠ͢ΔϞφυʢࣗ༝Ϟφυʴϕʔεؔख͔Β࡞੒ʣ typealias AsyncThrows<A> = Free<AsyncThrowsF, A> // try ΩʔϫʔυΛࣗ࡞ func try_<A>(_ r: Result<A, Error>) -> AsyncThrows<A> { .join(.try_(r, .unit)) } // await ΩʔϫʔυΛࣗ࡞ func await_<A>(_ a: Async<A>) -> AsyncThrows<A> { .join(.await_(a, .unit)) } /05& ͜ͷؔख͸͢Ͱʹ߹੒ࡁΈ͕ͩɺ ෼ղͯ͠߹੒ͤ͞Δ͜ͱ΋Մೳ ؔखϨϕϧͰ͸߹੒ՄೳͰɺ ϞφυϨϕϧͰ͸ग़དྷͳ͍ ݴޠ࢓༷ΩʔϫʔυΛ ࣗ࡞Ͱ͖Δʂ
  48. ࣗ༝ϞφυʹΑΔܭࢉޮՌͷ߹੒ let monad: AsyncThrows<Foo> = … AsyncThrows.do { monadResult <-

    await_(monad) monad_ <- try_(monadResult) is_ <- await_(monad_.is) just_ = await_(is_.just) a_ <- try_(just_.a) monoid_ <- await_(a_.monoid) return monoid_ } ࣗ༝ϞφυΛ࢖ͬͯ ݴޠ಺ʹಠࣗͷ%4-Λߏங ˣ USZ BXBJU྆ํΛؚΜͩ ݴޠ࢓༷ͷॻ͖ํͱ ΄΅มΘΒͳ͍ॻ͖ຯʹͳΔ
  49. let ast = AsyncThrows.do { /* લϖʔδ */ } Free.join(.await_(monad,

    { monadResult in Free.join(.try_(monadResult, { monad_ in Free.join(.await_(monad_.is, { is_ in Free.join(.await_(is_.just, { just_ in Free.join(.try_(just_.a, { a_ in Free.join(.await_(a_.monoid, { monoid_ in Free.unit(monoid_) })) })) })) })) })) })) ࣗ༝ϞφυʹΑͬͯɺ ݴޠ಺%4- ߏจ ΛߏஙͰ͖Δ ˠ͜ΕΛͲ͏lղऍz͢Δ͔͕࣍ͷ՝୊
  50. // AsyncThrows<A> ߏจ ͔Β࣮ࡍͷඇಉظܭࢉ Async<A> ʹม׵ʢղऍʣ͢Δ func runAST(_ ast: AsyncThrows<Bar>)

    -> Async<Bar> { iterate(ast) { (asyncThrowsF: AsyncThrowsF<Async<Bar>>) -> Async<Bar> in switch asyncThrowsF { case let .try_(result, callback): switch result { case let .success(value): return callback(value) // ੒ޭ࣌ʹίʔϧόοΫΛݺͿ case let .failure(error): return Bar(error) // ࣦഊ࣌ʹίʔϧόοΫΛݺ͹ͣૣظ୤ग़ } case let .await_(async_, callback): return async_.flatMap { callback($0) } // ඇಉظܭࢉ async_ ΛॲཧޙɺίʔϧόοΫΛݺͿ } } } // ࠶ؼతܭࢉ func iterate<A>(ast: AsyncThrows<A>, algebra: AsyncThrowsF<Async<A>> -> Async<A>) -> Async<A> { switch ast { case let .unit(a): return a case let .free(m): return algebra(m.map { iterate(ast: $0, algebra: algebra) }) } }
  51. ·ͱΊʢϞφυʣ wϞφυNBQ VOJU qBU.BQ Ϟφυଇ  wϞφυEPه๏Λ࢖͏ͱɺखଓ͖ʹมߋͰ͖Δ wࣗ༝ϞφυΛ࢖͏ͱɺUSZ BXBJUͷ߹੒͕ࣗ࡞Ͱ͖Δ wϞφυͱݴޠ࢓༷ʢखଓ͖ʷΩʔϫʔυʣ͸౳ՁͱΈͳͤ

    Δ wܭࢉޮՌʹϞφυʹݴޠ࢓༷Ωʔϫʔυ
  52. ܧଓ Continuation ! a POWER

  53. ܧଓ $POUJOVBUJPO ͱ͸ʁ wܧଓίʔϧόοΫؔ਺ɿܕ"3 wܧଓ౉͠ελΠϧ $14 ɿܕ "3 3 //

    ࠶ܝɿൃද๯಄ͷؔ਺ // fetch: Request -> (Result -> Void) -> Void func fetch( request: Request, completion: @escaping (Result<Response, Error>) -> Void ) -> Void ܧଓ $14 $POUJOVBUJPO1BTTJOH4UZMF ࢒ΓͷܭࢉʢίʔϧόοΫʣͷ͜ͱ ίʔϧόοΫ͕Ҿ਺ͷؔ਺
  54. ྫɿ4XJGU6OTBGF$POUJOVBUJPO // stdlib/public/Concurrency/PartialAsyncTask.swift // NOTE: Result Λແࢹͨ͠όʔδϣϯ // typealias UnsafeContinuation<T>

    = T -> Void struct UnsafeContinuation<T> { func resume(with value: T) } // withUnsafeContinuation: ((T -> Void) -> Void) -> Async<T> func withUnsafeContinuation<T>( _ fn: (UnsafeContinuation<T>) -> Void ) async -> T { ... } $14 $14͔Β"TZODؔ਺΁
  55. ௨ৗͷؔ਺ɿ௚઀ελΠϧ EJSFDUTUZMF // खଓ͖ (Ҿ਺ܕ͔ΒฦΓܕ΁ͷ direct style ͳؔ਺) let f:

    A -> B = ... let g: B -> C = ... let h: C -> D = ... func foo(a: A) -> D { let b = f(a) let c = g(b) let d = h(c) return d } // foo(a) == h(g(f(a)))
  56. ܧଓ౉͠ελΠϧ $14 // खଓ͖Λʮܧଓ౉͠ελΠϧʯʹม׵ func fooCPS<R>(a: A, completion: D ->

    R) -> R { return fCPS(a, { b in return gCPS(b, { c in return hCPS(c, { d in return completion(d) }) }) }) } $14 ௚઀ελΠϧͷίʔυͱ ಉ౳ͱΈͳͤΔ
  57. ܧଓ౉͠ελΠϧ $14 // ैདྷͷҾ਺ͱ completion Ҿ਺ͷॱংΛೖΕସ͑Δ + ΧϦʔԽ func fooCPS<R>(completion:

    D -> R) -> A -> R { return { a in return fCPS({ b in return gCPS({ c in return hCPS({ d in return completion(d) })(c) })(b) })(a) } } // fooCPS(completion) == fCPS(gCPS(hCPS(completion))) /05&͜ͷܗ΋ "%ʹର͢Δ$14
  58. // CPSม׵ ʹ ถాͷิ୊͔ΒಘΒΕΔʮถాຒΊࠐΈʯ // cf. iOSDC 2018 ݍ࿦ͱSwift΁ͷԠ༻ p.60

    func cpsTransform<X, Y, R>(_ xToY: X -> Y) -> (Y -> R) -> (X -> R) { return { yToR in return { x in yToR(xToY(x)) } } } let f: A -> B = ... let fCPS: (B -> R) -> (A -> R) = cpsTransform(f) let g: B -> C = ... let gCPS: (C -> R) -> (B -> R) = cpsTransform(g) let h: C -> D = ... let hCPS: (D -> R) -> (C -> R) = cpsTransform(h) let foo: A -> D = { a in h(g(f(a))) } let fooCPS: (D -> R) -> (A -> R) = { k in fCPS(gCPS(hCPS(k))) } $14ม׵ʹΑΓ ຤ඌ࠶ؼ࠷దԽͳͲ͕ߦ͑Δ
  59. ܧଓ౉͠ελΠϧ $14 // ؔ਺ͷ߹੒ʢྫɿ `(g ∘ f)(x) == g(f(x))`ʣ //

    NOTE: ࣮͸ `cpsTransform` ͷҾ਺ΛೖΕସ͑ͨόʔδϣϯ func ∘ <A, B, C>(_ g: B -> C, _ f: A -> B) -> A -> C { return { g(f($0)) } } // ௚઀ελΠϧ let foo = h ∘ g ∘ f // CPS (ܧଓ౉͠ελΠϧ) let fooCPS = fCPS ∘ gCPS ∘ hCPS ద༻ॱং͕ I$14ˠH$14ˠG$14 ͰٯʹͳΔ ؔ਺ద༻ͷॱং͸ӈ͔Β GˠHˠI
  60. // खଓ͖Λʮܧଓ౉͠ελΠϧʯʹม׵ func fooCPS<R>(a: A, completion: D -> R) ->

    R { return fCPS(a, { b in return gCPS(b, { c in return hCPS(c, { d in return completion(d) }) }) }) } ܧଓ౉͠ελΠϧʹΑΔܧଓͷٯ޲͖߹੒ GPP$14ͷ ܧଓ
  61. // खଓ͖Λʮܧଓ౉͠ελΠϧʯʹม׵ func fooCPS<R>(a: A, completion: D -> R) ->

    R { return fCPS(a, { b in return gCPS(b, { c in return hCPS(c, { d in return completion(d) }) }) }) } ܧଓ౉͠ελΠϧʹΑΔܧଓͷٯ޲͖߹੒ I$14ͷ ܧଓ
  62. // खଓ͖Λʮܧଓ౉͠ελΠϧʯʹม׵ func fooCPS<R>(a: A, completion: D -> R) ->

    R { return fCPS(a, { b in return gCPS(b, { c in return hCPS(c, { d in return completion(d) }) }) }) } ܧଓ౉͠ελΠϧʹΑΔܧଓͷٯ޲͖߹੒ H$14ͷ ܧଓ
  63. // खଓ͖Λʮܧଓ౉͠ελΠϧʯʹม׵ func fooCPS<R>(a: A, completion: D -> R) ->

    R { return fCPS(a, { b in return gCPS(b, { c in return hCPS(c, { d in return completion(d) }) }) }) } ܧଓ౉͠ελΠϧʹΑΔܧଓͷٯ޲͖߹੒ G$14ͷ ܧଓ
  64. $14ͷ߹੒͸ܧଓΛ Լ͔Β্ʹ޲͔ͬͯ߹੒͢Δ

  65. ܧଓϞφυ // ܧଓ౉ؔ͠਺ (CPS) Λ಺แ͢ΔܕɻશͯͷϞφυͷ฼ɻ // ถాͷิ୊ (A -> R)

    -> F<R> ≅ F<A> ʹ F = ߃౳ؔख Λద༻ͨ͠ͱ͖ͷࠨลɻ struct Cont<R, A> { let run: (A -> R) -> R } extension Monad[Cont<R, _>] { func flatMap<B>(_ f: A -> Cont<R, B>) -> Cont<R, B> { Cont<R, B> { k in self.run { a in f(a).run(k) } } } }
  66. ܧଓϞφυͷEPه๏≅௨ৗͷίʔυ // CPS Λdoه๏Ͱखଓ͖Խ Cont.do { monad_ <- monad is_

    <- monad_.is just_ <- is_.just a_ <- just_.a monoid_ <- a_.monoid return monoid_ } // ௚઀ελΠϧ func procedure() -> Bar { let monad_ = monad let is_ = monad_.is let just_ = is_.just let a_ = just_.a let monoid_ = a_.monoid return monoid_ } ≅ reflect reify
  67. // CPS Λdoه๏Ͱखଓ͖Խ Cont.do { monad_ <- monad is_ <-

    monad_.is just_ <- is_.just a_ <- just_.a monoid_ <- a_.monoid return monoid_ } // ௚઀ελΠϧ func procedure() -> Bar { let monad_ = monad let is_ = monad_.is let just_ = is_.just let a_ = just_.a let monoid_ = a_.monoid return monoid_ } ≅ reflect reify ܧଓϞφυͷEPه๏≅௨ৗͷίʔυ
  68. // CPS Λdoه๏Ͱखଓ͖Խ Cont.do { monad_ <- monad is_ <-

    monad_.is just_ <- is_.just a_ <- just_.a monoid_ <- a_.monoid return monoid_ } // ௚઀ελΠϧ func procedure() -> Bar { let monad_ = monad let is_ = monad_.is let just_ = is_.just let a_ = just_.a let monoid_ = a_.monoid return monoid_ } ≅ reflect reify ܧଓϞφυͷEPه๏≅௨ৗͷίʔυ
  69. // CPS Λdoه๏Ͱखଓ͖Խ Cont.do { monad_ <- monad is_ <-

    monad_.is just_ <- is_.just a_ <- just_.a monoid_ <- a_.monoid return monoid_ } // ௚઀ελΠϧ func procedure() -> Bar { let monad_ = monad let is_ = monad_.is let just_ = is_.just let a_ = just_.a let monoid_ = a_.monoid return monoid_ } ≅ reflect reify ܧଓϞφυͷEPه๏≅௨ৗͷίʔυ
  70. // CPS Λdoه๏Ͱखଓ͖Խ Cont.do { monad_ <- monad is_ <-

    monad_.is just_ <- is_.just a_ <- just_.a monoid_ <- a_.monoid return monoid_ } // ௚઀ελΠϧ func procedure() -> Bar { let monad_ = monad let is_ = monad_.is let just_ = is_.just let a_ = just_.a let monoid_ = a_.monoid return monoid_ } ≅ reflect reify ܧଓϞφυͷEPه๏≅௨ৗͷίʔυ
  71. // CPS Λdoه๏Ͱखଓ͖Խ Cont.do { monad_ <- monad is_ <-

    monad_.is just_ <- is_.just a_ <- just_.a monoid_ <- a_.monoid return monoid_ } // ௚઀ελΠϧ func procedure() -> Bar { let monad_ = monad let is_ = monad_.is let just_ = is_.just let a_ = just_.a let monoid_ = a_.monoid return monoid_ } ≅ reflect reify ܧଓϞφυͷEPه๏≅௨ৗͷίʔυ
  72. ༨ஊɿύΠϓԋࢉࢠc // Unix pipe ෩ͷԋࢉࢠ func |> <A, R>(a: A,

    f: A -> R) -> R { f(a) } // pipe ͷྫʢࠨ͔ΒӈʹಡΈ΍͍͢ʣ let str = 12 |> { $0 * 3 } |> String.init |> { $0 + "!" } // ࢀߟɿ௨ৗͷ direct style ͷॻ͖ํʢӈ͔Βࠨʹؔ਺ద༻ʣ let str = { $0 + "!" }(String.init({ $0 * 3 }(12))) $14 /05&qBU.BQ." ".3 .3 ʹ.߃౳ؔखΛ౰ͯͨ΋ͷͱΈͳͤΔ ʢ$14ͱϞφυ QJQFͱqBU.BQ͸ࣅ͍ͯΔʣ
  73. Structured Concurrency

  74. ैདྷ (SBOE$FOUSBM%JTQBUDI ͷඇಉظॲཧ Dispatch Queue 0 (Thread 0) queue1 queue1.async

    queue2 queue2.async RVFVF͕ఀࢭͯ͠΋ RVFVF͕ಈ࡞͠ଓ͚Δ ਌ࢠ ೖΕࢠ ؔ܎ʹͳ͘ɺ ඇಉظHPUP͍ͯ͠ΔΑ͏ͳ΋ͷ
  75. 4USVDUVSFE$PODVSSFODZʹΑΔඇಉظॲཧ task0 task1 task0.addTask task2 task1.addTask UBTL͕ఀࢭ͢Δ·Ͱ UBTL͕ಈ࡞͠ଓ͚Δ ਌ࢠ ೖΕࢠ

    ؔ܎ɺ ίϧʔνϯ΍Ωϟϯηϧͷ ఻ൖ͕Մೳ
  76. ܧଓʹΑΔϦιʔε؅ཧ // Ϧιʔεͷ֬อͱղ์Λߦ͏ɻ`bracket` ؔ਺ͱ΋ݴ͏ɻ // IO ͸෭࡞༻ʢPromise/Observable ͷΑ͏ͳ΋ͷʣ func retainRelease<A,

    B, C>(retain value: IO<A>, release: A -> IO<B>) -> Cont<IO<C>, A> { Cont { k in value.flatMap { a in k(a).flatMapError { _ in release(a) } .flatMap { r in release(a).map { _ in r } } } } }
  77. // Ϧιʔε؅ཧͷྫɿෳ਺ϑΝΠϧૢ࡞ func openFile(_ filename: String) -> IO<FileHandle> { ...

    } let value = retainRelease( retain: openFile("1.txt"), release: { $0.closeFile() } ).run { handle1 in // ಡΈऔΓॲཧ ... retainRelease( retain: openFile("2.txt"), release: { $0.closeFile() } ).run { handle2 in // ॻ͖ࠐΈॲཧ ... } // είʔϓΛൈ͚Δͱ handle2.closeFile() } // είʔϓΛൈ͚Δͱ handle1.closeFile() IBOEMFͷ ੜଘظؒ͸ ඞͣIBOEMFͷ ੜଘظؒ಺ʹऩ·Δ IBOEMFͷ ੜଘظؒ IBOEMFͷ ੜଘظؒ
  78. // Swift Structured Concurrency // (ඇಉظॲཧͷೖΕࢠߏ଄ɺCancellation ͷ఻ൖ) let asyncValues =

    retainRelease( // withTaskGroup retain: makeTaskGroup(), release: { $0.cancelAll() } ).run { taskGroup in for i in 0 ..< 10 { taskGroup.addTask( retainRelease( // withTaskCancellationHandler retain: makeTask(i), release: { $0.cancel() } ) ) } var values = [] for await value in taskGroup { // ݸʑͷ Task ׬ྃ & release values += [value] } return values } // είʔϓΛൈ͚Δͱ TaskGroup release ֤5BTLͷ ੜଘظؒ 5BTL(SPVQͷ ੜଘظؒ
  79. CallCC Ca%-wi&-current-continuation

  80. /// Continuation. typealias Cont<R, A> = (@escaping (A) -> R)

    -> R /// /// Call with Current Continuation. /// - Peirce: `((A → B) → A) → A` /// - CallCC: `((A → M<B>) → M<A>) → M<A>` /// /// - Note: `callCC` is like control operators e.g. `goto`, `return`, `throw`. /// func callCC<A, B, R>( _ f: @escaping (_ exit: @escaping (A) -> Cont<R, B>) -> Cont<R, A> ) -> Cont<R, A> { { outer in f { a in { _ in outer(a) } }(outer) } } J04%$ 4XJGUͱ࿦ཧʙͦͯ͠ؼ͖ͬͯͨݍ࿦ʙ IUUQTTQFBLFSEFDLDPNJOBNJZTXJGUBOEMPHJD BOEDBUFHPSZUIFPSZ
  81. DBMM$$Λ࢖ͬͨܭࢉޮՌ SFUVSOCSFBLHVBSE // Early exit Cont.do { print("1") value <-

    callCC { exit in Cont.do { print("2") exit("3 (done)") // return / break / guard print("͜͜͸ݺ͹Εͳ͍") } } print(value) }
  82. DBMM$$Λ࢖ͬͨܭࢉޮՌ EFGFS // Deferred call Cont.do { print("1") k <-

    callCC { exit in Cont.do { print("2") exit({ _ in print("4 (deferred done)") }) } } print("3") k() }
  83. DBMM$$Λ࢖ͬͨܭࢉޮՌ ΤϥʔϋϯυϦϯά // Error handling let value: Double? = Cont.do

    { let x: Double = 1 let y: Double = 0 // or non-zero callCC { exitOK in Cont.do { error <- callCC { exitError in Cont.do { return y == 0 ? exitError("Can't be divided by 0") : exitOK(x / y) } } print(error) // Τϥʔ͕ى͖ͨ৔߹ͷΈ௨Δ return nil }} }
  84. ༨ஊɿTIJGUSFTFU ݶఆܧଓ wDBMM$$͸ʮϓϩάϥϜͷ࢒ΓͷܭࢉશͯʯΛଋറ͢ΔͷͰɺѻ͍͕େมةݥ wTIJGUSFTFU ݶఆܧଓ Λ࢖͏ͱɺଋറ͢ΔܧଓͷൣғΛݶఆతʹͰ͖Δ wʮDBMM$$ʯʴʮՄมࢀরʯʹݶఆܧଓʹϞφυͱಉ౳ͷܭࢉޮՌ func reset<A, R>(_

    m: Cont<A, A>) -> Cont<R, A> { Cont { k in k(m.run { $0 }) } } func shift<A, R>(_ f: (A -> R) -> Cont<R, R>) -> Cont<R, A> { Cont { k in f(k).run { $0 } } }
  85. ༨ஊɿTIJGUSFTFUͷྫ let value = Cont.do { x <- reset(Cont.do {

    y <- shift { k in Cont.do { // k = { $0 + 3 } z <- k(10) return k(z) // k Λෳ਺ճ࣮ߦ͢Δ͜ͱ΋Մೳ }} return y + 3 // ޙଓͷ͜ͷίʔυ͕ k ʹଋറ͞ΕΔ }) return x - 1 // reset ͷ֎ͳͷͰ k ʹଋറ͞Εͳ͍ } // value = ((10 + 3) + 3) - 1 = 15
  86. ·ͱΊʢܧଓͱ$14ʣ wܧଓίʔϧόοΫʹ࢒Γͷܭࢉ w$14ܧଓ౉͠ελΠϧίʔϧόοΫ͕Ҿ਺ͷؔ਺ wܧଓͷྫɿύΠϓॲཧɺ4USVDUVSFE$PODVSSFODZ wDBMM$$ͱTIJGUSFTFUɿϞφυͱಉ౳ͷܭࢉޮՌ wϞφυΛ࢖Θͳͯ͘΋ɺܧଓΛ࢖ͬͯܭࢉޮՌΛߟ͑Δ͜ ͱ͕Ͱ͖Δ

  87. ίϧʔνϯ Cooperative multitasking

  88. ίϧʔνϯͱ͸ʁ func getVaccine1() { print("ϫΫ☆") // (1) pause() // தஅɿ੍ޚ͕

    getVaccine2 ʹҠΔ print("νϯ☆") // (3) } func getVaccine2() { print("ϫΫ☆") // (2) pause() // தஅɿ੍ޚ͕ getVaccine1 ͷதஅϙΠϯτʹ໭Δ print("νϯ☆") // (4) } runCoroutines(getVaccine1, getVaccine2) // ϫΫνϯ2ճ઀छ // 1 → 2 → 3 → 4 ͷॱͰʢҎԼུʣ தஅɾ࠶։Ͱ͖ΔػೳΛ࣋ͭؔ਺ͷ͜ͱ ڠௐతϚϧνλεΫ
  89. func getVaccine1() { print("ϫΫ☆") // (1) pause() // தஅɿ੍ޚ͕ getVaccine2

    ʹҠΔ print("νϯ☆") // (3) } func getVaccine2() { print("ϫΫ☆") // (2) pause() // தஅɿ੍ޚ͕ getVaccine1 ͷதஅϙΠϯτʹ໭Δ print("νϯ☆") // (4) } runCoroutines(getVaccine1, getVaccine2) // ϫΫνϯ2ճ઀छ // 1 → 2 → 3 → 4 ͷॱͰʢҎԼུʣ ίϧʔνϯͱ͸ʁ
  90. func getVaccine1() { print("ϫΫ☆") // (1) pause() // தஅɿ੍ޚ͕ getVaccine2

    ʹҠΔ print("νϯ☆") // (3) } func getVaccine2() { print("ϫΫ☆") // (2) pause() // தஅɿ੍ޚ͕ getVaccine1 ͷதஅϙΠϯτʹ໭Δ print("νϯ☆") // (4) } runCoroutines(getVaccine1, getVaccine2) // ϫΫνϯ2ճ઀छ // 1 → 2 → 3 → 4 ͷॱͰʢҎԼུʣ ίϧʔνϯͱ͸ʁ
  91. func getVaccine1() { print("ϫΫ☆") // (1) pause() // தஅɿ੍ޚ͕ getVaccine2

    ʹҠΔ print("νϯ☆") // (3) } func getVaccine2() { print("ϫΫ☆") // (2) pause() // தஅɿ੍ޚ͕ getVaccine1 ͷதஅϙΠϯτʹ໭Δ print("νϯ☆") // (4) } runCoroutines(getVaccine1, getVaccine2) // ϫΫνϯ2ճ઀छ // 1 → 2 → 3 → 4 ͷॱͰʢҎԼུʣ ίϧʔνϯͱ͸ʁ
  92. func getVaccine1() { print("ϫΫ☆") // (1) pause() // தஅɿ੍ޚ͕ getVaccine2

    ʹҠΔ print("νϯ☆") // (3) } func getVaccine2() { print("ϫΫ☆") // (2) pause() // தஅɿ੍ޚ͕ getVaccine1 ͷதஅϙΠϯτʹ໭Δ print("νϯ☆") // (4) } runCoroutines(getVaccine1, getVaccine2) // ϫΫνϯ2ճ઀छ // 1 → 2 → 3 → 4 ͷॱͰʢҎԼུʣ ίϧʔνϯͱ͸ʁ
  93. func getVaccine1() { print("ϫΫ☆") // (1) pause() // தஅɿ੍ޚ͕ getVaccine2

    ʹҠΔ print("νϯ☆") // (3) } func getVaccine2() { print("ϫΫ☆") // (2) pause() // தஅɿ੍ޚ͕ getVaccine1 ͷதஅϙΠϯτʹ໭Δ print("νϯ☆") // (4) } runCoroutines(getVaccine1, getVaccine2) // ϫΫνϯ2ճ઀छ // 1 → 2 → 3 → 4 ͷॱͰʢҎԼུʣ ίϧʔνϯͱ͸ʁ
  94. func getVaccine1() { print("ϫΫ☆") // (1) pause() // தஅɿ੍ޚ͕ getVaccine2

    ʹҠΔ print("νϯ☆") // (3) } func getVaccine2() { print("ϫΫ☆") // (2) pause() // தஅɿ੍ޚ͕ getVaccine1 ͷதஅϙΠϯτʹ໭Δ print("νϯ☆") // (4) } runCoroutines(getVaccine1, getVaccine2) // ϫΫνϯ2ճ઀छ // 1 → 2 → 3 → 4 ͷॱͰʢҎԼུʣ ίϧʔνϯͱ͸ʁ
  95. func receiver() { // தஅɿ receive Ͱ੍ޚ͕தஅ͠ɺsender ʹҠΔ // ࠶։ɿ

    money Λड͚औͬͯ࣍ͷߦ΁ money /* (4) */ <- receive() // (1) accountA += money // (5) } // (6) func sender() { accountB -= money // (2) // தஅɿ send Ͱ money ΛૹΓɺ੍ޚ͕ receiver ʹ໭Δ send(money) // (3) } // (7) runCoroutines(receiver, sender) // accountB͔Β͓͕ۚҾ͔Εɺૹۚ͞ΕɺaccountAʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ ίϧʔνϯͷྫɿσʔλͷड͚౉͠ ʲڠௐతϚϧνλεΫʳ ҟͳΔλεΫ͕ಉ͡εϨουͰ ަޓʹߦΘΕΔͷͰ σʔλڝ߹ʹͳΒͳ͍
  96. func receiver() { // தஅɿ receive Ͱ੍ޚ͕தஅ͠ɺsender ʹҠΔ // ࠶։ɿ

    money Λड͚औͬͯ࣍ͷߦ΁ money /* (4) */ <- receive() // (1) accountA += money // (5) } // (6) func sender() { accountB -= money // (2) // தஅɿ send Ͱ money ΛૹΓɺ੍ޚ͕ receiver ʹ໭Δ send(money) // (3) } // (7) runCoroutines(receiver, sender) // accountB͔Β͓͕ۚҾ͔Εɺૹۚ͞ΕɺaccountAʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ ίϧʔνϯͷྫɿσʔλͷड͚౉͠
  97. func receiver() { // தஅɿ receive Ͱ੍ޚ͕தஅ͠ɺsender ʹҠΔ // ࠶։ɿ

    money Λड͚औͬͯ࣍ͷߦ΁ money /* (4) */ <- receive() // (1) accountA += money // (5) } // (6) func sender() { accountB -= money // (2) // தஅɿ send Ͱ money ΛૹΓɺ੍ޚ͕ receiver ʹ໭Δ send(money) // (3) } // (7) runCoroutines(receiver, sender) // accountB͔Β͓͕ۚҾ͔Εɺૹۚ͞ΕɺaccountAʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ ίϧʔνϯͷྫɿσʔλͷड͚౉͠
  98. func receiver() { // தஅɿ receive Ͱ੍ޚ͕தஅ͠ɺsender ʹҠΔ // ࠶։ɿ

    money Λड͚औͬͯ࣍ͷߦ΁ money /* (4) */ <- receive() // (1) accountA += money // (5) } // (6) func sender() { accountB -= money // (2) // தஅɿ send Ͱ money ΛૹΓɺ੍ޚ͕ receiver ʹ໭Δ send(money) // (3) } // (7) runCoroutines(receiver, sender) // accountB͔Β͓͕ۚҾ͔Εɺૹۚ͞ΕɺaccountAʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ ίϧʔνϯͷྫɿσʔλͷड͚౉͠
  99. func receiver() { // தஅɿ receive Ͱ੍ޚ͕தஅ͠ɺsender ʹҠΔ // ࠶։ɿ

    money Λड͚औͬͯ࣍ͷߦ΁ money /* (4) */ <- receive() // (1) accountA += money // (5) } // (6) func sender() { accountB -= money // (2) // தஅɿ send Ͱ money ΛૹΓɺ੍ޚ͕ receiver ʹ໭Δ send(money) // (3) } // (7) runCoroutines(receiver, sender) // accountB͔Β͓͕ۚҾ͔Εɺૹۚ͞ΕɺaccountAʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ ίϧʔνϯͷྫɿσʔλͷड͚౉͠
  100. func receiver() { // தஅɿ receive Ͱ੍ޚ͕தஅ͠ɺsender ʹҠΔ // ࠶։ɿ

    money Λड͚औͬͯ࣍ͷߦ΁ money /* (4) */ <- receive() // (1) accountA += money // (5) } // (6) func sender() { accountB -= money // (2) // தஅɿ send Ͱ money ΛૹΓɺ੍ޚ͕ receiver ʹ໭Δ send(money) // (3) } // (7) runCoroutines(receiver, sender) // accountB͔Β͓͕ۚҾ͔Εɺૹۚ͞ΕɺaccountAʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ ίϧʔνϯͷྫɿσʔλͷड͚౉͠
  101. func receiver() { // தஅɿ receive Ͱ੍ޚ͕தஅ͠ɺsender ʹҠΔ // ࠶։ɿ

    money Λड͚औͬͯ࣍ͷߦ΁ money /* (4) */ <- receive() // (1) accountA += money // (5) } // (6) func sender() { accountB -= money // (2) // தஅɿ send Ͱ money ΛૹΓɺ੍ޚ͕ receiver ʹ໭Δ send(money) // (3) } // (7) runCoroutines(receiver, sender) // accountB͔Β͓͕ۚҾ͔Εɺૹۚ͞ΕɺaccountAʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ ίϧʔνϯͷྫɿσʔλͷड͚౉͠
  102. func receiver() { // தஅɿ receive Ͱ੍ޚ͕தஅ͠ɺsender ʹҠΔ // ࠶։ɿ

    money Λड͚औͬͯ࣍ͷߦ΁ money /* (4) */ <- receive() // (1) accountA += money // (5) } // (6) func sender() { accountB -= money // (2) // தஅɿ send Ͱ money ΛૹΓɺ੍ޚ͕ receiver ʹ໭Δ send(money) // (3) } // (7) runCoroutines(receiver, sender) // accountB͔Β͓͕ۚҾ͔Εɺૹۚ͞ΕɺaccountAʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ ίϧʔνϯͷྫɿσʔλͷड͚౉͠
  103. ࣗ༝ϞφυΛ࢖ͬͨίϧʔνϯ /// ෭࡞༻ M Λ෇͚ͨࣗ༝Ϟφυͱಉ͡ߏ଄ struct Coroutine<F, M, A> {

    let resume: M<State> indirect enum State { case done(A) // AΛฦͯ͠ऴྃ͢ΔλεΫ case suspended(F<Coroutine<F, M, A>>) // F ʹแ·Ε͍ͯΔɺதஅ͞ΕͨλεΫ } } extension Monad[Coroutine<F, M, _>] where Functor[F], Monad[M] { func flatMap<B>(_ f: A -> Coroutine<F, M, B>) -> Coroutine<F, M, B> { self.resume.flatMap { state in switch state { case let .done(a): return f(a).resume case let .suspended(fco): return M.unit(.suspended(fco.map { $0.flatMap(f) })) } } } } લճͷࣗ༝Ϟφυ'SFF' "ʹ ෭࡞༻.͕௥Ճ͞Εͨܗ ࣗ༝Ϟφυม׵ࢠ
  104. ίϧʔνϯม׵ؔ਺ TVTQFOEMJGU /// F Ͱఆٛ͞ΕͨܭࢉޮՌͷϕʔεߏ଄Λ suspended ঢ়ଶͷίϧʔνϯʹม׵ func suspend<F, M,

    A>(_ fco: F<Coroutine<F, M, A>>) -> Coroutine<F, M, A> where Functor[F], Monad[M] { Coroutine(M.unit(.suspended(fco))) } /// ෭࡞༻ M Λίϧʔνϯʹม׵ func lift<F, M, A>(_ effect: M<A>) -> Coroutine<F, M, A> where Functor[F], Monad[M] { Coroutine(effect.map(.done)) }
  105. 1BVTFίϧʔνϯϞφυ // pauseԋࢉΛߏ੒͢Δϕʔεؔख struct PauseF<Next> { let next: Next }

    // Trampoline ͱ΋ݺ͹ΕΔ typealias Pause<M, A> = Coroutine<PauseF, M, A> // NOTE: pauseॲཧʹ suspend ؔ਺͕࢖ΘΕΔ func pause() -> Pause<M, Void> where Monad[M] { suspend(PauseF(.unit(()))) }
  106. 1BVTFίϧʔνϯϞφυʹΑΔ࣮૷ let getVaccine = lift(print("ϫΫ☆")) .flatMap { pause() } .flatMap

    { lift(print(“νϯ☆")) } // ·ͨ͸ do ه๏Λ࢖ͬͯ let getVaccine = Pause.do { lift(print("ϫΫ☆")) pause() lift(print("νϯ☆")) } runCoroutines(getVaccine, getVaccine) ࠷ॳͷखଓ͖ͷྫͱ ΄΅ಉ͡ܗ
  107. // ༨ஊɿrunCoroutines ͷத਎͸ʁ extension Applicative[Coroutine<F, M, _>] where Functor[F], Monad[M]

    { static func zipWith(_ f: A -> B -> C) -> Coroutine<F, M, A> -> Coroutine<F, M, B> -> Coroutine<F, M, C> { { coroutineA in { coroutineB in coroutineA.flatMap { a in coroutineB.flatMap { b in .unit(f(a)(b)) } } } } } } func runCoroutines<M, A>(_ pauses: [Pause<M, A>]) -> M<[A]> where Monad[M] { func run(_ pause: Pause<M, A>) -> M<A> where Monad[M] { pause.resume.flatMap { state in switch state in { case let .done(arr): return M.unit(arr) case let .suspended(fco): return run(fco.next) } } } let combined = pauses.reduce(Pause.unit([])) { acc, pause in Pause.zipWith({ [$0] + $1 })(pause)(acc) } return run(combined) } ഑ྻͷ[JQͱߟ͑ํ͸ಉ͡ ͭͷ$PSPVUJOFΛʮ$14ͷ഑ྻʯ ʹݟཱͯɺ$14ϖΞͷ഑ྻΛ࡞Δ ͜͜Ͱ͸͞ΒʹGͰϖΞΛ$ʹม׵͢Δ $14ϖΞͷ഑ྻΛ ʮڠௐతʯʹ࣮ߦ͢Δ
  108. 4FOEίϧʔνϯϞφυ // sendԋࢉΛߏ੒͢Δϕʔεؔख struct SendF<A, Next> { let send: (A,

    Next) } // Generator ͱ΋ݺ͹ΕΔ typealias Send<Money, M, A> = Coroutine<SendF<Money>, M, A> // NOTE: sendॲཧʹ suspend ؔ਺͕࢖ΘΕΔ func send<Money>(money: Money) -> Send<Money, M, Void> where Monad[M] { suspend(SendF(money, .unit(()))) }
  109. 3FDFJWFίϧʔνϯϞφυ // receiveԋࢉΛߏ੒͢Δϕʔεؔख struct ReceiveF<A, Next> { let receive: A

    -> Next } // Iteratee ͱ΋ݺ͹ΕΔ typealias Receive<Money, M, A> = Coroutine<ReceiveF<Money>, M, A> // NOTE: receiveॲཧʹ suspend ؔ਺͕࢖ΘΕΔ func receive<Money>() -> Receive<Money, M, Money> where Monad[M] { suspend(ReceiveF(.unit)) }
  110. // Send-Receive ίϧʔνϯϞφυʹΑΔ࣮૷ let sender = Send.do { accountA -=

    money send(money) } let receiver = Receive.do { money <- receive() accountB += money } runCoroutines(sender, receiver) // ༨ஊɿrunCoroutine ͷத਎ (NOTE: fatalError Λ࢖Θͳ͍޻෉΋Ͱ͖Δ) func runCoroutines<Money, M, A, B>(sender: Send<Money, M, A>, receiver: Receive<Money, M, B>) -> M<(A, B)> where Monad[M] { sender.resume.flatMap { sent in receiver.resume.flatMap { received in switch (sent, received) { case let (.done(a), .done(b)): return .unit((a, b)) case let (.done(a), .suspended(fco)): fatalError("sender ended too soon") case let (.suspended(a, co), .done(b)): return runCoroutines(co, .unit(b)) case let (.suspended(a, co), .suspended(f)): return runCoroutines(co, f(a)) } } } }
  111. ࠶ܝɿ"TZOD5ISPXTࣗ༝Ϟφυ // try & await ੍ޚԋࢉࢠΛߏ੒͢Δϕʔεؔख enum AsyncThrowsF<Next> { case

    try_<Value>(Result<Value, Error>, Value -> Next) case await_<Value>(Async<Value>, Value -> Next) } typealias AsyncThrows<A> = Free<AsyncThrowsF, A> func try_<A>(_ r: Result<A, Error>) -> AsyncThrows<A> { .join(.try_(r, .unit)) } func await_<A>(_ a: Async<A>) -> AsyncThrows<A> { .join(.await_(a, .unit)) }
  112. "TZOD$PSPVUJOF // awaitԋࢉͷΈΛߏ੒͢Δϕʔεؔख struct AsyncF<Next> { let await_<Value>: (Async<Value>, Value

    -> Next) } typealias AsyncCoroutine<M, A> = Coroutine<AsyncF, M, A> // NOTE: awaitॲཧʹ suspend ؔ਺͕࢖ΘΕΔ func await_<A>(_ a: Async<A>) -> AsyncCoroutine<A> { suspend(AsyncF(a, .unit)) }
  113. "TZOD$PSPVUJOF // t = 19 Ͱ྆ํͷ஋Λड͚औΔ (2ͭͷฒྻ async let +

    await ʹ૬౰) let asyncValues: Async<(C1, C2)> = runCoroutines( AsyncCoroutine.do { a1 <- await_(task1a(sleep: 2)) // (1) at t = 0 b1 <- await_(task1b(a1, sleep: 3)) // (4) at t = 2 c1 <- await_(task1c(b1, sleep: 8)) // (5) at t = 5 return c1 // (7) at t = 13 }, AsyncCoroutine.do { a2 <- await_(task2a(sleep: 1)) // (2) at t = 0 b2 <- await_(task2b(a2, sleep: 5)) // (3) at t = 1 c2 <- await_(task2c(b2, sleep: 13)) // (6) at t = 6 return c2 // (8) at t = 19 } ) BXBJU@ TVTQFOE ࣌ʹ੍ޚ͕SVO$PSPVUJOFTʹ໭Γɺ ඇಉظܭࢉΛεέδϡʔϦϯά ίʔϧόοΫ ܧଓ Λอଘ ˠ׬ྃޙʹܧଓΛݺͼɺ੍ޚΛ໭͢ @$PODVSSFODZ಺෦࣮૷ /05&$PSPVUJOFϞφυ ࣗ༝Ϟφυ Λ࢖Θͣɺ ܧଓϞφυ ঢ়ଶϞφυͰදݱ͢Δํ๏΋͋Δ
  114. ·ͱΊʢίϧʔνϯʣ wίϧʔνϯதஅɾ࠶։Ͱ͖ΔػೳΛ࣋ͭؔ਺ wࣗ༝Ϟφυม׵ࢠΛ࢖ͬͯίϧʔνϯΛදݱͰ͖Δ wKPJO͕TVTQFOEػೳΛ࣋ͭ wBXBJUͷਖ਼ମ͸TVTQFOE w"TZODSVO$PSPVUJOFT͸@$PODVSSFODZϥϯλΠϜ಺ʹ࣮૷  w/05&ʮܧଓϞφυ ঢ়ଶϞφυʯʹΑΔɺܧଓͷώʔϓ্Ͱͷ؅ཧ ͷํ͕@$PODVSSFODZͷຊདྷͷ࣮૷ʹ͍͔ۙ΋

    88%$
  115. BTZODBXBJUΛ஌ΔͨΊʹ͸ ίϧʔνϯ͕ඞཁ ίϧʔνϯΛ஌ΔͨΊʹ͸ Ϟφυͱܧଓͷཧղ͕ෆՄܽ Swift 5.5

  116. ୯ͳΔࣗݾؔखͷݍʹ͓͚Δ ϞϊΠυର৅ͩΑ ܧଓJTύϫʔ ڠௐతͳൃදΛ໨ࢦͯ͠ ͕Μ͹Γ·͢ Ϟφυ ܧଓ ίϧʔνϯ

  117. "MHFCSBJD&⒎FDUTͳͲ ݶఆܧଓ ϞφυΛEJSFDUTUZMFʹ͢Δ &GGFDU )BOEMFST %FMJNJUFE $POUJOVBUJPO .POBEJD 3FqFDUJPO

  118. ࢀߟจݙ BQQMFTXJGU 4XJGU$PNNVOJUZ • SE-0296 Async/await • SE-0300 Continuations for

    interfacing async tasks with synchronous code • SE-0304 Structured concurrency • SE-0317 async let bindings • Swift concurrency: Behind the scenes - WWDC21 • Explore structured concurrency in Swift - WWDC21 • Meet async/await in Swift - WWDC21 • Coroutines in LLVM • Zewo/Venice • belozierov/SwiftCoroutine • Swift Language Updates - Learn Languages 2021
  119. ࢀߟจݙ Ϟφυ • ശͰߟ͑ΔFunctorɺApplicativeͦͯ͠Monad - Qiita • Functor, Applicative, Monad

    | haskell • Free Monad | haskell • A Neighborhood of Infinity: The Mother of all Monads • The Comonad.Reader » Free Monads for Less (Part 1 of 3): Codensity • Eugenio Moggi. 1991. Notions of computation and monads • Philip Wadler. 1994. Monads and composable continuations • Philip Wadler. 1995. Monads for functional programming • Gordon Plotkin and John Power. 2002. Notions of Computation Determine Monads • W Swierstra. 2008. Data types a la carte. • Janis Voigtländer. 2008. Asymptotic Improvement of Computations over Free Monads • O Kiselyov, A Sabry, C Swords. 2013. Extensible effects: an alternative to monad transformers • E Rivas and M Jaskelioff. 2017. Notions of computation as monoids.
  120. ࢀߟจݙ ܧଓɺ$14 • Haskell/Continuation passing style - Wikibooks, open books

    for an open world • continuation-passing style in nLab • ܧଓ | haskell • ܧଓ౉͠ͳHaskellϥΠϑ - ϞφυͱΘͨ͠ ͱίϞφυ • ܧଓϞφυʹΑΔϦιʔε؅ཧ - Qiita • Scala ʹ͓͚ΔܧଓϞφυͷ࣮૷ͱ׆༻ - Speaker Deck • Deep Dive async/await in Unity with UniTask(UniRx.Async) • ฒߦϓϩάϥϛϯάͱܧଓϞφυ • ઙҪ ݈Ұ. shift/reset ϓϩάϥϛϯάೖ໳ • Kenichi Asai. 2009. On typing delimited continuations: three new solutions to the printf problem • Continuations and Delimited Control • The Monad.Reader/Issue2/ FunWithLinearImplicitParameters
  121. ࢀߟจݙ 4USVDUVSFE$PODVSSFODZ • 250bpm: Structured Concurrency • Notes on structured

    concurrency, or: Go statement considered harmful — njs blog • Structured concurrency | by Roman Elizarov | Medium • Roman Elizarov — Structured concurrency - YouTube
  122. ࢀߟจݙ ίϧʔνϯ • Mario Blazevic. 2011. Coroutine Pipelines. The Monad.Reader

    Issue 19 • CoroutineϞφυͱεςʔτϚγϯ - The curse of λ • stackfulness of coroutines - lilyum ensemble • Introduction to the C++ coroutines | C++ - don't panic! • 20෼͘Β͍ͰΘ͔ͬͨؾ෼ʹͳΕΔC++20ίϧʔ νϯ • Coroutines guide | Kotlin • 2016 LLVM Developers’ Meeting: G. Nishanov “LLVM Coroutines” - YouTube • 2018 LLVM Developers’ Meeting: J. McCall “Coroutine Representations and ABIs in LLVM” - YouTube • GeeCON 2019: Dmitry Kandalov - Coroutines explained by example - YouTube • Functorial Blog - Stackless Coroutines in PureScript • Functorial Blog - Extensible Coeffects • Roshan James and Amr Sabry. 2011. Yield: Mainstream Delimited Continuations • R. P. Pieters and T. Schrijvers. 2020. Faster Coroutine Pipelines: A Reconstruction
  123. ࢀߟจݙ "EWBODFEUPQJDT • Andrzej Filinski. 1989. Declarative Continuations and Categorical

    Duality • O Danvy, A Filinski. 1992. Representing control: A study of the CPS transformation • Andrzej Filinski. 1994. Representing Monads. • Andrzej Filinski. 1999. Representing layered monads. • Carl Bruggeman et al. 1996. Representing control in the presence of one-shot continuations • Gordon Plotkin and Matija Pretnar. 2009. Handlers of algebraic effects. • Matija Pretnar. 2015. An Introduction to Algebraic Effects and Handlers • yallop/effects-bibliography • S. Kawahara, et al. 2020. One-shot Algebraic Effects as Coroutines • ܧଓͱ͔ͷ࿩୊αʔϕΠ | κeenͷHappy Hacκing Blog • Ploeg & Kiselyov. 2014. Reflection without Remorse • Monadic Reflection in Haskell • ϞφυΛͭ͘Ζ͏ • Monadic Reflectionʹ͍ͭͯ - Arantium Maestum • Y. Forster, et al. 2017. On the Expressive Power of User- Defined Effects Effect Handlers, Monadic Reflection, Delimited Control. • Toru Kawata. 2018. A Contextual Reconstruction of Monadic Reflection.
  124. Thanks! Yasuhiro Inami @inamiy