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

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

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

Yasuhiro Inami

September 18, 2021
Tweet

More Decks by Yasuhiro Inami

Other Decks in Programming

Transcript

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

    View full-size slide

  2. ඇಉظܭࢉ

    View full-size slide

  3. ίʔϧόοΫํࣜʹΑΔඇಉظܭࢉ
    func fetch(
    request: Request,
    completion: @escaping (Result) -> 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()
    }

    View full-size slide

  4. ίʔϧόοΫ஍ࠈ
    fetch1(request1) { response1 in
    fetch2(response1) { response2 in
    fetch3(response2) { response3 in
    fetch4(response3) { response4 in
    fetch5(response4) { response5 in
    print(response5)
    }
    }
    }
    }
    }

    View full-size slide

  5. ϦΞΫςΟϒɾϓϩάϥϛϯάʹΑΔඇಉظܭࢉ
    func fetch(request: Request) -> Observable {
    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() }
    }
    }

    View full-size slide

  6. 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)
    })

    View full-size slide

  7. 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ΩʔϫʔυͰ
    ඇಉظܭࢉΛ଴ͭ

    View full-size slide

  8. 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)
    }

    View full-size slide

  9. ඇಉظܭࢉ͍Ζ͍Ζ
    wίʔϧόοΫํࣜ
    w1SPNJTF'VUVSFɺϦΞΫςΟϒɾϓϩάϥϛϯά
    wBTZODBXBJU खଓ͖

    ࣮͸ͲΕ΋ಉ͡Α͏ͳ΋ͷͱΈͳͤΔʂ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    IUUQTTQFBLFSEFDLDPNJOBNJZOVNCFSDBUQH

    View full-size slide

  15. Ϟφυ J04%$ΑΓ

    protocol Monad[M] where Functor[M] {
    static func unit(_ c: C) -> M
    static func join(_ mmc: M>) -> M
    }
    extension Monad {
    static func init_() -> M {
    .unit(())
    }
    static func flatMap(_ f: C -> M)
    -> M -> M {
    return { .join(map(f)($0)) }
    }
    }
    'VODUPS ؔख
    ͷTVCQSPUPDPM
    'VODUPS͸NBQΛ࣋ͭ
    Ϟφυ͸͞Βʹ
    VOJUPSJOJU@
    KPJOPSqBU.BQ
    Λ࣋ͭ

    View full-size slide

  16. Ϟφυͷྫɿ0QUJPOBM
    enum Optional {
    case none
    case some(T)
    init(_ some: T) // unit: T -> Optional
    func map(_ transform: (T) -> U) -> U?
    func flatMap(_ transform: (T) -> U?) -> U?
    }
    VOJU NBQ qBU.BQΛ࣋ͭͷͰɺ
    0QUJPOBM͸Ϟφυ

    View full-size slide

  17. Ϟφυͷྫɿ"SSBZ
    struct Array {
    init() // init_: () -> Array
    func map(_ transform: (T) -> U) -> [U]
    func flatMap(_ transform: (T) -> [U]) -> [U]
    }
    JOJU@ NBQ qBU.BQΛ࣋ͭͷͰɺ
    "SSBZ͸Ϟφυ

    View full-size slide

  18. Ϟφυͷྫɿ3Y0CTFSWBCMF
    struct Observable {
    // unit: T -> Observable
    static func just(_ element: T)
    func map(_ transform: (T) -> U)
    -> Observable
    func flatMap(_ transform: (T) -> Observable)
    -> Observable
    }
    VOJU NBQ qBU.BQΛ࣋ͭͷͰɺ
    0CTFSWBCMF͸Ϟφυ

    View full-size slide

  19. Ϟφυଇ
    // ࠨ୯Ґݩ
    unit(a).flatMap(f) == f(a)
    // ӈ୯Ґݩ
    monad.flatMap(unit) == monad
    // ݁߹཯
    monad.flatMap(f).flatMap(g)
    == monad.flatMap { f($0).flatMap(g) }

    View full-size slide

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

    View full-size slide

  21. Ϟφυଇͷ݁߹཯
    // ݁߹཯ͷࠨล
    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)
    }
    }
    }
    }
    }
    ==

    View full-size slide

  22. Ϟφυ͸
    ίʔϧόοΫ஍ࠈΛ
    ϝιουνΣʔϯʹม׵͢Δ

    View full-size slide

  23. qBU.BQνΣʔϯͷྫɿ0QUJPOBM$IBJOJOH
    let monad: Optional = …
    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 }
    ==

    View full-size slide

  24. qBU.BQνΣʔϯͷྫɿ0QUJPOBM$IBJOJOH
    monad
    ?.is
    ?.just
    ?.a
    ?.monoid
    monad
    .flatMap(\.is)
    .flatMap(\.just)
    .flatMap(\.a)
    .flatMap(\.monoid)
    ==
    let monad: Optional = …
    let bar = monad?.is?.just?.a?.monoid 4&
    ,FZ1BUI&YQSFTTJPOT
    BT'VODUJPOT

    View full-size slide

  25. 0QUJPOBM$IBJOJOHͷʮʁʯ͸
    qBU.BQ ,FZ1BUI
    HFUUFS

    View full-size slide

  26. qBU.BQνΣʔϯͷྫɿ3FTVMU
    let monad: Result = …
    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νΣʔϯ͢Δ
    Ҏ֎ͷॻ͖ํ͸͋Δ͔ʁ

    View full-size slide

  27. 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ʹ૬౰

    View full-size slide

  28. 2ඇಉظܭࢉ΋ಉ͡࿮૊ΈͰ
    ߟ͑Δ͜ͱ͕Ͱ͖Δʁ
    ˣ
    "ͦΕ͕BTZODBXBJU

    View full-size slide

  29. qBU.BQνΣʔϯͷྫɿ"TZOD
    let monad: Async = …
    monad
    .flatMap { $0.is }
    .flatMap { $0.just }
    .flatMap { $0.a }
    .flatMap { $0.monoid }
    "TZODඇಉظϞφυ͕
    ͋ΔͱԾఆ͢Δ
    1SPNJTF'VUVSF0CTFSWBCMF
    ͱಉ͡ͱࢥͬͯྑ͍

    2ϕλʹqBU.BQνΣʔϯ͢Δ
    Ҏ֎ͷॻ͖ํ͸͋Δ͔ʁ

    View full-size slide

  30. 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Λ࢖͏

    View full-size slide

  31. ͜͜·Ͱͷ·ͱΊʢϞφυʣ
    wϞφυɿNBQVOJUqBU.BQ Ϟφυଇ

    wϞφυ݁߹཯ɿίʔϧόοΫ஍ࠈΛϝιουνΣʔϯʹม׵
    w0QUJPOBMɿqBU.BQ˱A Aԋࢉࢠ
    w3FTVMUɿqBU.BQ˱USZΩʔϫʔυ
    w"TZODɿqBU.BQ˱BXBJUΩʔϫʔυ
    ʮϞφυʯͱ
    ʮݴޠ࢓༷
    ʢखଓ͖ͱΩʔϫʔυʣʯ
    ʹରԠؔ܎͕͋Δʂ

    View full-size slide

  32. ܭࢉޮՌ
    Computational Effect

    View full-size slide

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

    View full-size slide

  34. ܭࢉޮՌͷྫ
    wΤϥʔϋϯυϦϯά 3FTVMU UISPXTUSZ

    wඇಉظܭࢉ "TZOD1SPNJTF0CTFSWBCMF
    BTZODBXBJU

    wঢ়ଶߋ৽ 4UBUF

    wඇܾఆੑܭࢉ "SSBZ
    ͳͲ

    View full-size slide

  35. 2Ϟφυͱݴޠ࢓༷ͷ
    ΪϟοϓΛຒΊΔʹ͸ʁ

    View full-size slide

  36. EPه๏
    do-notation

    View full-size slide

  37. ࠶ܝɿqBU.BQνΣʔϯͷྫɿ3FTVMU
    let monad: Result = …
    monad
    .flatMap { $0.is }
    .flatMap { $0.just }
    .flatMap { $0.a }
    .flatMap { $0.monoid }

    View full-size slide

  38. 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νΣʔϯΛ
    खଓ͖ॲཧʹݟͤΔ౶ҥߏจ

    View full-size slide

  39. "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ʹݟཱͯɺ
    ଋറม਺Λࠨଆʹஔ͘

    View full-size slide

  40. Ϟφυ͸
    EPه๏ʹΑͬͯ
    खଓ͖ॲཧʹมܗͰ͖Δ
    ˣ
    2Ϟφυͱݴޠ࢓༷͸ͲͪΒ΋
    ʮखଓ͖ʯͱΈͳͤΔͷͰಉ͡ʁ

    View full-size slide

  41. Ϟφυͷ໰୊఺ɿܭࢉޮՌͷ߹੒
    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_
    }
    BTZODUISPXTͷ߹੒

    View full-size slide

  42. // Ϟφυ͕ෳ਺ʹωετ͍ͯ͠Δ৔߹ɺ߹੒ܭࢉͷѻ͍͕େม
    let monad: Async> = …
    // 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पΓͷ
    ΤϥʔϋϯυϦϯά্͕ख͘දݱͰ͖ͳ͍
    ˣ
    Ϟφυ͸ѻ͍ʹ͍͘ʂ

    View full-size slide

  43. Ϟφυͷ߹੒໰୊ʹର͢Δղܾࡦ͍Ζ͍Ζ
    wϞφυม׵ࢠ .POBE5SBOTGPSNFS

    w5BHMFTT'JOBM
    wࣗ༝Ϟφυ$PQSPEVDU ؔखͷ௚࿨

    w&YUFOTJCMF&GGFDU
    wࣗ༝Ϟφυ0QFO6OJPO
    w$PZPOFEB ༨ถా
    ࣗ༝Ϟφυ0QFO6OJPO

    View full-size slide

  44. ࣗ༝Ϟφυ 'SFF.POBE

    // ࣗ༝Ϟφυɿunit ͱ join ͕࠶ؼతσʔλߏ଄಺ʹఆٛ͞Ε͍ͯΔ
    indirect enum Free {
    case unit(A)
    case join(F>)
    }
    extension Monad[Free] where Functor[F] {
    func flatMap(_ f: A -> Free) -> Free {
    switch self {
    case let .unit(a): return f(a)
    case let .join(x): return .join(x.map { $0.flatMap(f) })
    }
    }
    }
    ؔख'Λ༩͑Δͱɺͦͷߏ଄ʹରԠͨ͠
    ΠΠײ͡ͷϞφυ͕खʹೖΔ

    View full-size slide

  45. // try & await ੍ޚԋࢉࢠΛߏ੒͢Δϕʔεؔख
    // NOTE: `Value -> Next` ͕ίʔϧόοΫʹ૬౰
    enum AsyncThrowsF {
    // NOTE: ͸ case಺δΣωϦΫεʢٙࣅSwiftʣ
    case try_(Result, Value -> Next)
    case await_(Async, Value -> Next)
    }
    // async + throws ͷ྆ํʹରԠ͢ΔϞφυʢࣗ༝Ϟφυʴϕʔεؔख͔Β࡞੒ʣ
    typealias AsyncThrows = Free
    // try ΩʔϫʔυΛࣗ࡞
    func try_(_ r: Result) -> AsyncThrows {
    .join(.try_(r, .unit))
    }
    // await ΩʔϫʔυΛࣗ࡞
    func await_(_ a: Async) -> AsyncThrows {
    .join(.await_(a, .unit))
    }
    /05&
    ͜ͷؔख͸͢Ͱʹ߹੒ࡁΈ͕ͩɺ
    ෼ղͯ͠߹੒ͤ͞Δ͜ͱ΋Մೳ
    ؔखϨϕϧͰ͸߹੒ՄೳͰɺ
    ϞφυϨϕϧͰ͸ग़དྷͳ͍

    ݴޠ࢓༷ΩʔϫʔυΛ
    ࣗ࡞Ͱ͖Δʂ

    View full-size slide

  46. ࣗ༝ϞφυʹΑΔܭࢉޮՌͷ߹੒
    let monad: AsyncThrows = …
    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-Λߏங
    ˣ
    USZBXBJU྆ํΛؚΜͩ
    ݴޠ࢓༷ͷॻ͖ํͱ
    ΄΅มΘΒͳ͍ॻ͖ຯʹͳΔ

    View full-size slide

  47. 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͢Δ͔͕࣍ͷ՝୊

    View full-size slide

  48. // AsyncThrows ߏจ ͔Β࣮ࡍͷඇಉظܭࢉ Async ʹม׵ʢղऍʣ͢Δ
    func runAST(_ ast: AsyncThrows) -> Async {
    iterate(ast) { (asyncThrowsF: AsyncThrowsF>) -> Async 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(ast: AsyncThrows, algebra: AsyncThrowsF> -> Async) -> Async {
    switch ast {
    case let .unit(a):
    return a
    case let .free(m):
    return algebra(m.map { iterate(ast: $0, algebra: algebra) })
    }
    }

    View full-size slide

  49. ·ͱΊʢϞφυʣ
    wϞφυNBQVOJUqBU.BQ Ϟφυଇ

    wϞφυEPه๏Λ࢖͏ͱɺखଓ͖ʹมߋͰ͖Δ
    wࣗ༝ϞφυΛ࢖͏ͱɺUSZBXBJUͷ߹੒͕ࣗ࡞Ͱ͖Δ
    wϞφυͱݴޠ࢓༷ʢखଓ͖ʷΩʔϫʔυʣ͸౳ՁͱΈͳͤ
    Δ
    wܭࢉޮՌʹϞφυʹݴޠ࢓༷Ωʔϫʔυ

    View full-size slide

  50. ܧଓ
    Continuation ! a POWER

    View full-size slide

  51. ܧଓ $POUJOVBUJPO
    ͱ͸ʁ
    wܧଓίʔϧόοΫؔ਺ɿܕ"3
    wܧଓ౉͠ελΠϧ $14
    ɿܕ "3
    3
    // ࠶ܝɿൃද๯಄ͷؔ਺
    // fetch: Request -> (Result -> Void) -> Void
    func fetch(
    request: Request,
    completion: @escaping (Result) -> Void
    ) -> Void
    ܧଓ
    $14
    $POUJOVBUJPO1BTTJOH4UZMF
    ࢒ΓͷܭࢉʢίʔϧόοΫʣͷ͜ͱ
    ίʔϧόοΫ͕Ҿ਺ͷؔ਺

    View full-size slide

  52. ྫɿ4XJGU6OTBGF$POUJOVBUJPO
    // stdlib/public/Concurrency/PartialAsyncTask.swift
    // NOTE: Result Λແࢹͨ͠όʔδϣϯ
    // typealias UnsafeContinuation = T -> Void
    struct UnsafeContinuation {
    func resume(with value: T)
    }
    // withUnsafeContinuation: ((T -> Void) -> Void) -> Async
    func withUnsafeContinuation(
    _ fn: (UnsafeContinuation) -> Void
    ) async -> T {
    ...
    }
    $14
    $14͔Β"TZODؔ਺΁

    View full-size slide

  53. ௨ৗͷؔ਺ɿ௚઀ελΠϧ 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)))

    View full-size slide

  54. ܧଓ౉͠ελΠϧ $14

    // खଓ͖Λʮܧଓ౉͠ελΠϧʯʹม׵
    func fooCPS(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
    ௚઀ελΠϧͷίʔυͱ
    ಉ౳ͱΈͳͤΔ

    View full-size slide

  55. ܧଓ౉͠ελΠϧ $14

    // ैདྷͷҾ਺ͱ completion Ҿ਺ͷॱংΛೖΕସ͑Δ + ΧϦʔԽ
    func fooCPS(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

    View full-size slide

  56. // CPSม׵ ʹ ถాͷิ୊͔ΒಘΒΕΔʮถాຒΊࠐΈʯ
    // cf. iOSDC 2018 ݍ࿦ͱSwift΁ͷԠ༻ p.60
    func cpsTransform(_ 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ม׵ʹΑΓ
    ຤ඌ࠶ؼ࠷దԽͳͲ͕ߦ͑Δ

    View full-size slide

  57. ܧଓ౉͠ελΠϧ $14

    // ؔ਺ͷ߹੒ʢྫɿ `(g ∘ f)(x) == g(f(x))`ʣ
    // NOTE: ࣮͸ `cpsTransform` ͷҾ਺ΛೖΕସ͑ͨόʔδϣϯ
    func ∘ (_ 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

    View full-size slide

  58. // खଓ͖Λʮܧଓ౉͠ελΠϧʯʹม׵
    func fooCPS(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ͷ
    ܧଓ

    View full-size slide

  59. // खଓ͖Λʮܧଓ౉͠ελΠϧʯʹม׵
    func fooCPS(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ͷ
    ܧଓ

    View full-size slide

  60. // खଓ͖Λʮܧଓ౉͠ελΠϧʯʹม׵
    func fooCPS(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ͷ
    ܧଓ

    View full-size slide

  61. // खଓ͖Λʮܧଓ౉͠ελΠϧʯʹม׵
    func fooCPS(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ͷ
    ܧଓ

    View full-size slide

  62. $14ͷ߹੒͸ܧଓΛ
    Լ͔Β্ʹ޲͔ͬͯ߹੒͢Δ

    View full-size slide

  63. ܧଓϞφυ
    // ܧଓ౉ؔ͠਺ (CPS) Λ಺แ͢ΔܕɻશͯͷϞφυͷ฼ɻ
    // ถాͷิ୊ (A -> R) -> F ≅ F ʹ F = ߃౳ؔख Λద༻ͨ͠ͱ͖ͷࠨลɻ
    struct Cont {
    let run: (A -> R) -> R
    }
    extension Monad[Cont] {
    func flatMap(_ f: A -> Cont) -> Cont {
    Cont { k in
    self.run { a in f(a).run(k) }
    }
    }
    }

    View full-size slide

  64. ܧଓϞφυͷ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

    View full-size slide

  65. // 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ه๏≅௨ৗͷίʔυ

    View full-size slide

  66. // 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ه๏≅௨ৗͷίʔυ

    View full-size slide

  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ه๏≅௨ৗͷίʔυ

    View full-size slide

  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ه๏≅௨ৗͷίʔυ

    View full-size slide

  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ه๏≅௨ৗͷίʔυ

    View full-size slide

  70. ༨ஊɿύΠϓԋࢉࢠc
    // Unix pipe ෩ͷԋࢉࢠ
    func |> (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͸ࣅ͍ͯΔʣ

    View full-size slide

  71. Structured
    Concurrency

    View full-size slide

  72. ैདྷ (SBOE$FOUSBM%JTQBUDI
    ͷඇಉظॲཧ
    Dispatch
    Queue 0
    (Thread 0)
    queue1
    queue1.async
    queue2
    queue2.async
    RVFVF͕ఀࢭͯ͠΋
    RVFVF͕ಈ࡞͠ଓ͚Δ
    ਌ࢠ ೖΕࢠ
    ؔ܎ʹͳ͘ɺ
    ඇಉظHPUP͍ͯ͠ΔΑ͏ͳ΋ͷ

    View full-size slide

  73. 4USVDUVSFE$PODVSSFODZʹΑΔඇಉظॲཧ
    task0
    task1
    task0.addTask
    task2
    task1.addTask
    UBTL͕ఀࢭ͢Δ·Ͱ
    UBTL͕ಈ࡞͠ଓ͚Δ
    ਌ࢠ ೖΕࢠ
    ؔ܎ɺ
    ίϧʔνϯ΍Ωϟϯηϧͷ
    ఻ൖ͕Մೳ

    View full-size slide

  74. ܧଓʹΑΔϦιʔε؅ཧ
    // Ϧιʔεͷ֬อͱղ์Λߦ͏ɻ`bracket` ؔ਺ͱ΋ݴ͏ɻ
    // IO ͸෭࡞༻ʢPromise/Observable ͷΑ͏ͳ΋ͷʣ
    func retainRelease(retain value: IO, release: A -> IO)
    -> Cont, A> {
    Cont { k in
    value.flatMap { a in
    k(a).flatMapError { _ in release(a) }
    .flatMap { r in
    release(a).map { _ in r }
    }
    }
    }
    }

    View full-size slide

  75. // Ϧιʔε؅ཧͷྫɿෳ਺ϑΝΠϧૢ࡞
    func openFile(_ filename: String) -> IO { ... }
    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ͷ
    ੜଘظؒ

    View full-size slide

  76. // 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ͷ
    ੜଘظؒ

    View full-size slide

  77. CallCC
    Ca%-wi&-current-continuation

    View full-size slide

  78. /// Continuation.
    typealias Cont = (@escaping (A) -> R) -> R
    ///
    /// Call with Current Continuation.
    /// - Peirce: `((A → B) → A) → A`
    /// - CallCC: `((A → M) → M) → M`
    ///
    /// - Note: `callCC` is like control operators e.g. `goto`, `return`, `throw`.
    ///
    func callCC(
    _ f: @escaping (_ exit: @escaping (A) -> Cont) -> Cont
    ) -> Cont
    {
    { outer in
    f { a in { _ in outer(a) } }(outer)
    }
    }
    J04%$
    4XJGUͱ࿦ཧʙͦͯ͠ؼ͖ͬͯͨݍ࿦ʙ
    IUUQTTQFBLFSEFDLDPNJOBNJZTXJGUBOEMPHJD
    BOEDBUFHPSZUIFPSZ

    View full-size slide

  79. 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)
    }

    View full-size slide

  80. 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()
    }

    View full-size slide

  81. 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
    }}
    }

    View full-size slide

  82. ༨ஊɿTIJGUSFTFU ݶఆܧଓ

    wDBMM$$͸ʮϓϩάϥϜͷ࢒ΓͷܭࢉશͯʯΛଋറ͢ΔͷͰɺѻ͍͕େมةݥ
    wTIJGUSFTFU ݶఆܧଓ
    Λ࢖͏ͱɺଋറ͢ΔܧଓͷൣғΛݶఆతʹͰ͖Δ
    wʮDBMM$$ʯʴʮՄมࢀরʯʹݶఆܧଓʹϞφυͱಉ౳ͷܭࢉޮՌ
    func reset(_ m: Cont) -> Cont {
    Cont { k in k(m.run { $0 }) }
    }
    func shift(_ f: (A -> R) -> Cont) -> Cont {
    Cont { k in f(k).run { $0 } }
    }

    View full-size slide

  83. ༨ஊɿ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

    View full-size slide

  84. ·ͱΊʢܧଓͱ$14ʣ
    wܧଓίʔϧόοΫʹ࢒Γͷܭࢉ
    w$14ܧଓ౉͠ελΠϧίʔϧόοΫ͕Ҿ਺ͷؔ਺
    wܧଓͷྫɿύΠϓॲཧɺ4USVDUVSFE$PODVSSFODZ
    wDBMM$$ͱTIJGUSFTFUɿϞφυͱಉ౳ͷܭࢉޮՌ
    wϞφυΛ࢖Θͳͯ͘΋ɺܧଓΛ࢖ͬͯܭࢉޮՌΛߟ͑Δ͜
    ͱ͕Ͱ͖Δ

    View full-size slide

  85. ίϧʔνϯ
    Cooperative multitasking

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  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 ͷॱͰʢҎԼུʣ
    ίϧʔνϯͱ͸ʁ

    View full-size slide

  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 ͷॱͰʢҎԼུʣ
    ίϧʔνϯͱ͸ʁ

    View full-size slide

  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 ͷॱͰʢҎԼུʣ
    ίϧʔνϯͱ͸ʁ

    View full-size slide

  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 ͷॱͰʢҎԼུʣ
    ίϧʔνϯͱ͸ʁ

    View full-size slide

  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 ͷॱͰʢҎԼུʣ
    ίϧʔνϯͱ͸ʁ

    View full-size slide

  93. 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ʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ
    ίϧʔνϯͷྫɿσʔλͷड͚౉͠
    ʲڠௐతϚϧνλεΫʳ
    ҟͳΔλεΫ͕ಉ͡εϨουͰ
    ަޓʹߦΘΕΔͷͰ
    σʔλڝ߹ʹͳΒͳ͍

    View full-size slide

  94. 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ʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ
    ίϧʔνϯͷྫɿσʔλͷड͚౉͠

    View full-size slide

  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ʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ
    ίϧʔνϯͷྫɿσʔλͷड͚౉͠

    View full-size slide

  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ʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ
    ίϧʔνϯͷྫɿσʔλͷड͚౉͠

    View full-size slide

  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ʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ
    ίϧʔνϯͷྫɿσʔλͷड͚౉͠

    View full-size slide

  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ʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ
    ίϧʔνϯͷྫɿσʔλͷड͚౉͠

    View full-size slide

  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ʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ
    ίϧʔνϯͷྫɿσʔλͷड͚౉͠

    View full-size slide

  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ʹ͓͕ۚೖΔʢ͜ͷؒʹׂΓࠐΈ͕ൃੜ͠ͳ͍ʣ
    ίϧʔνϯͷྫɿσʔλͷड͚౉͠

    View full-size slide

  101. ࣗ༝ϞφυΛ࢖ͬͨίϧʔνϯ
    /// ෭࡞༻ M Λ෇͚ͨࣗ༝Ϟφυͱಉ͡ߏ଄
    struct Coroutine {
    let resume: M
    indirect enum State {
    case done(A) // AΛฦͯ͠ऴྃ͢ΔλεΫ
    case suspended(F>) // F ʹแ·Ε͍ͯΔɺதஅ͞ΕͨλεΫ
    }
    }
    extension Monad[Coroutine] where Functor[F], Monad[M] {
    func flatMap(_ f: A -> Coroutine) -> Coroutine {
    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' "ʹ
    ෭࡞༻.͕௥Ճ͞Εͨܗ
    ࣗ༝Ϟφυม׵ࢠ

    View full-size slide

  102. ίϧʔνϯม׵ؔ਺ TVTQFOEMJGU

    /// F Ͱఆٛ͞ΕͨܭࢉޮՌͷϕʔεߏ଄Λ suspended ঢ়ଶͷίϧʔνϯʹม׵
    func suspend(_ fco: F>)
    -> Coroutine
    where Functor[F], Monad[M]
    {
    Coroutine(M.unit(.suspended(fco)))
    }
    /// ෭࡞༻ M Λίϧʔνϯʹม׵
    func lift(_ effect: M) -> Coroutine
    where Functor[F], Monad[M]
    {
    Coroutine(effect.map(.done))
    }

    View full-size slide

  103. 1BVTFίϧʔνϯϞφυ
    // pauseԋࢉΛߏ੒͢Δϕʔεؔख
    struct PauseF {
    let next: Next
    }
    // Trampoline ͱ΋ݺ͹ΕΔ
    typealias Pause = Coroutine
    // NOTE: pauseॲཧʹ suspend ؔ਺͕࢖ΘΕΔ
    func pause() -> Pause where Monad[M] {
    suspend(PauseF(.unit(())))
    }

    View full-size slide

  104. 1BVTFίϧʔνϯϞφυʹΑΔ࣮૷
    let getVaccine = lift(print("ϫΫ☆"))
    .flatMap { pause() }
    .flatMap { lift(print(“νϯ☆")) }
    // ·ͨ͸ do ه๏Λ࢖ͬͯ
    let getVaccine = Pause.do {
    lift(print("ϫΫ☆"))
    pause()
    lift(print("νϯ☆"))
    }
    runCoroutines(getVaccine, getVaccine)
    ࠷ॳͷखଓ͖ͷྫͱ
    ΄΅ಉ͡ܗ

    View full-size slide

  105. // ༨ஊɿrunCoroutines ͷத਎͸ʁ
    extension Applicative[Coroutine] where Functor[F], Monad[M] {
    static func zipWith(_ f: A -> B -> C)
    -> Coroutine -> Coroutine -> Coroutine {
    { coroutineA in { coroutineB in
    coroutineA.flatMap { a in
    coroutineB.flatMap { b in
    .unit(f(a)(b))
    }
    }
    } }
    }
    }
    func runCoroutines(_ pauses: [Pause]) -> M<[A]> where Monad[M] {
    func run(_ pause: Pause) -> M 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ϖΞͷ഑ྻΛ
    ʮڠௐతʯʹ࣮ߦ͢Δ

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  108. // 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(sender: Send, receiver: Receive)
    -> 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))
    }
    }
    }
    }

    View full-size slide

  109. ࠶ܝɿ"TZOD5ISPXTࣗ༝Ϟφυ
    // try & await ੍ޚԋࢉࢠΛߏ੒͢Δϕʔεؔख
    enum AsyncThrowsF {
    case try_(Result, Value -> Next)
    case await_(Async, Value -> Next)
    }
    typealias AsyncThrows = Free
    func try_(_ r: Result) -> AsyncThrows {
    .join(.try_(r, .unit))
    }
    func await_(_ a: Async) -> AsyncThrows {
    .join(.await_(a, .unit))
    }

    View full-size slide

  110. "TZOD$PSPVUJOF
    // awaitԋࢉͷΈΛߏ੒͢Δϕʔεؔख
    struct AsyncF {
    let await_: (Async, Value -> Next)
    }
    typealias AsyncCoroutine = Coroutine
    // NOTE: awaitॲཧʹ suspend ؔ਺͕࢖ΘΕΔ
    func await_(_ a: Async) -> AsyncCoroutine {
    suspend(AsyncF(a, .unit))
    }

    View full-size slide

  111. "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Ϟφυ ࣗ༝Ϟφυ
    Λ࢖Θͣɺ
    ܧଓϞφυঢ়ଶϞφυͰදݱ͢Δํ๏΋͋Δ

    View full-size slide

  112. ·ͱΊʢίϧʔνϯʣ
    wίϧʔνϯதஅɾ࠶։Ͱ͖ΔػೳΛ࣋ͭؔ਺
    wࣗ༝Ϟφυม׵ࢠΛ࢖ͬͯίϧʔνϯΛදݱͰ͖Δ
    wKPJO͕TVTQFOEػೳΛ࣋ͭ
    wBXBJUͷਖ਼ମ͸TVTQFOE
    w"TZODSVO$PSPVUJOFT͸@$PODVSSFODZϥϯλΠϜ಺ʹ࣮૷

    w/05&ʮܧଓϞφυঢ়ଶϞφυʯʹΑΔɺܧଓͷώʔϓ্Ͱͷ؅ཧ
    ͷํ͕@$PODVSSFODZͷຊདྷͷ࣮૷ʹ͍͔ۙ΋ 88%$

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  116. ࢀߟจݙ 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

    View full-size slide

  117. ࢀߟจݙ Ϟφυ

    • ശͰߟ͑Δ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.

    View full-size slide

  118. ࢀߟจݙ ܧଓɺ$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

    View full-size slide

  119. ࢀߟจݙ 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

    View full-size slide

  120. ࢀߟจݙ ίϧʔνϯ

    • 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

    View full-size slide

  121. ࢀߟจݙ "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.

    View full-size slide

  122. Thanks!
    Yasuhiro Inami
    @inamiy

    View full-size slide