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

iOSDC2018.pdf

Yuki Yasoshima
August 31, 2018
1.6k

 iOSDC2018.pdf

Yuki Yasoshima

August 31, 2018
Tweet

Transcript

  1. 4XJGUͷίʔυ͔Β
    ঢ়ଶભҠਤΛࣗಈͰੜ੒͠
    ܧଓతʹϝϯςφϯε͠΍͘͢͢Δ
    J04%$+BQBO
    IUUQTHJUIVCDPNPCKFDUJWFBVEJPJ04%$

    View Slide

  2. εςʔτϚγϯ
    ʢ༗ݶΦʔτϚτϯʣ
    ঢ়ଶͱભҠͱಈ࡞ͷ૊Έ߹Θ͔ͤΒͳΔ
    ৼΔ෣͍ͷϞσϧ

    View Slide

  3. ྫɿυΞͷ։ด

    View Slide

  4. ด͍ͯ͡Δ ։͍͍ͯΔ
    ։͘
    ด͡Δ

    View Slide

  5. ด͍ͯ͡Δ ։͍͍ͯΔ
    ։͘
    ด͡Δ
    ঢ়ଶ ঢ়ଶ

    View Slide

  6. ด͍ͯ͡Δ ։͍͍ͯΔ
    ։͘
    ด͡Δ
    ಈ࡞
    ಈ࡞

    View Slide

  7. ด͍ͯ͡Δ ։͍͍ͯΔ
    ։͘
    ด͡Δ
    ભҠ
    ભҠ

    View Slide

  8. ด͍ͯ͡Δ ։͍͍ͯΔ
    ։͘
    ด͡Δ

    View Slide

  9. ด͍ͯ͡Δ ։͍͍ͯΔ
    ։͘
    ด͡Δ
    υΞͷ։ดͷঢ়ଶભҠਤ

    View Slide

  10. ৼΔ෣͍Λίʔυʹ͢Δ

    View Slide

  11. εςʔτύλʔϯ
    Ϋϥεʹڞ௨ͷΠϯλʔϑΣʔεΛఆٛͯ͠
    ΠϯελϯεΛೖΕସ͑ͯৼΔ෣͍Λม͑Δ

    View Slide

  12. ໰୊
    શମͷભҠ͕Θ͔Γʹ͍͘
    ࣗ༝౓͕ߴ͗͢Δ
    Ϋϥε͕૿͑͗͢Δ

    View Slide

  13. ղܾࡦ
    ঢ়ଶભҠਤΛ࡞Δ

    View Slide

  14. ܧଓతʹίʔυͱਤΛ߹ΘͤΔͷ͕େม
    ໰୊

    View Slide

  15. VJqPX
    IUUQTHJUIVCDPNIJSPLJEBJDIJVJqPX
    [࠷ॳʹ]
    Ϣʔβʔ͕ݟΔ΋ͷΛॻ͖·͢ɻ
    --
    Ϣʔβʔ͕͢ΔߦಈΛॻ͖·͢ɻ
    [࣍ʹ]
    Ϣʔβʔ͕ݟΔ΋ͷ
    --
    Ϣʔβʔ͕͢Δ͜ͱ̍
    ==> ͦͷ݁Ռ̍
    Ϣʔβʔ͕͢Δ͜ͱ̎
    ==> ͦͷ݁Ռ̎
    [ͦͷ݁Ռ̍]
    ݁Ռ
    [ͦͷ݁Ռ̎]
    ݁Ռ

    View Slide

  16. "45
    IUUQTTQFBLFSEFDLDPNLJTIJLBXBLBUTVNJBTUNFUBQSPHSBNNJOHJOTXJGU
    AST meta-programming in Swift
    try! Swift Tokyo 2018
    Abstract Syntax Tree

    View Slide

  17. 'MPX(SBQI
    4XJGUͷεςʔτϚγϯϥΠϒϥϦ
    IUUQTHJUIVCDPNPCKFDUJWFBVEJP4XJGU'MPX(SBQI

    View Slide

  18. 'MPX(SBQI%PU$POWFSUFS
    'MPX(SBQIͰॻ͔Εͨίʔυ͔Β
    (SBQIWJ[ͷϑΝΠϧܗࣜʹॻ͖ग़͢
    ίϚϯυϥΠϯπʔϧ
    IUUQTHJUIVCDPNPCKFDUJWFBVEJP'MPX(SBQI%PU$POWFSUFS

    View Slide

  19. digraph {
    graph [label = "Door",
    labelloc = "t", labeljust = "l",
    fontcolor = "#333333", rankdir =
    "TB", fontname = "Osaka-Mono",
    fontsize = "12", charset =
    "UTF-8"]
    node [fontcolor = "#333333",
    fillcolor = "#F9F9F9", fontname =
    "Osaka-Mono", style =
    "solid,filled", fontsize = "10",
    color = "#CCCCCC"]
    edge [fontcolor = "#333333",
    fontname = "Osaka-Mono", fontsize
    = "9", color = "#AAAAAA"]
    opened [shape = "record",
    label = "{opened|։͍͍ͯΔ}", color
    = "#BBBBBB"]
    closing [shape = "record",
    label = "{closing|ด͡Δ}", color =
    "#40C5EE"]
    closed [shape = "record",
    label = "{closed|ด͍ͯ͡Δ}", color
    = "#00D54B"]
    opening [shape = "record",
    label = "{opening|։͘}", color =
    "#40C5EE"]
    "opened" -> "closing" [style =
    "solid", color = "#99DEF3"]
    "closing" -> "closed" [style =
    "dashed", color = "#AAAAAA"]
    "closed" -> "opening" [style =
    "solid", color = "#99DEF3"]
    //
    // Door.swift
    //
    import FlowGraph
    // υΞͷঢ়ଶ
    class Door: FlowGraphType {
    private(set) var isOpen: Bool = false {
    didSet {
    print("isOpen \(self.isOpen)")
    if let handler = self.isOpenHandler {
    handler(self.isOpen)
    }
    }
    }
    var isOpenHandler: ((Bool) -> Void)?
    enum WaitingState {
    case closed
    case opened
    }
    enum RunningState {
    case opening
    case closing
    }
    enum EventKind {
    case open
    case close
    }
    typealias Event = (kind: EventKind, object: Door)
    private let graph: FlowGraph
    init() {
    let builder = FlowGraphBuilder()
    // ด͍ͯ͡Δ
    builder.add(waiting: .closed) { event in
    if case .open = event.kind {
    return .run(.opening, event)
    } else {
    return .stay
    }
    }
    // ։͍͍ͯΔ
    builder.add(waiting: .opened) { event in
    if case .close = event.kind {
    return .run(.closing, event)
    } else {
    return .stay
    }
    }
    %PPSTXJGU %PPSEPU %PPSTWH

    View Slide

  20. γΣϧεΫϦϓτͰ
    ΍͍ͬͯΔ͜ͱ

    View Slide

  21. $ brew install graphviz
    (SBQIWJ[ΛΠϯετʔϧ
    $POWFSUFSͷ४උ
    )PNFCSFXΛΠϯετʔϧʢͷ֬ೝʣ

    View Slide

  22. $ swift build -c release
    $ swift run -c release FlowGraphDotConverter
    ೖྗ͢ΔϑΝΠϧʢෳ਺ʣ--output ग़ྗ͢ΔϑΥϧμ
    $ dot -T svg ೖྗ͢Δύε -o ग़ྗ͢Δύε
    Ϗϧυ͢Δʢ4XJGU1BDLBHF.BOBHFSʣ
    4XJGUϑΝΠϧΛղੳͯ͠(SBQIWJ[ͷܗࣜʹग़ྗ
    (SBQIWJ[Ͱਤʹม׵͢Δ
    $POWFSUFSͷ࣮ߦ

    View Slide

  23. 'MPX(SBQI

    View Slide

  24. 'MPX(SBQI%PPS
    DMPTFE PQFOFE
    DMPTJOH
    PQFOJOH
    &WFOU
    $VSSFOU

    View Slide

  25. 'MPX(SBQI%PPS
    DMPTFE PQFOFE
    8BJUJOH4UBUF
    ଴ػ͢Δεςʔτ
    ֎෦͔ΒΠϕϯτΛड͚औ࣮ͬͯߦ͞ΕΔΫϩʔδϟΛ࣋ͭ
    &WFOU
    DMPTJOH
    ʢด͍ͯ͡Δʣ ʢ։͍͍ͯΔʣ

    View Slide

  26. 'MPX(SBQI%PPS
    DMPTFE PQFOFE
    Πϕϯτ
    3VOOJOH4UBUF
    ॲཧΛ࣮ߦ͢Δεςʔτ
    8BJUJOH4UBUF͔ΒΠϕϯτΛ
    ड͚औ࣮ͬͯߦ͞ΕΔ
    ΫϩʔδϟΛ࣋ͭ
    ଴ػ͢Δ͜ͱ͸Ͱ͖ͳ͍
    DMPTJOH
    PQFOJOH
    ʢ։͘ʣ
    ʢด͡Δʣ

    View Slide

  27. 'MPX(SBQI%PPS
    DMPTFE PQFOFE
    &WFOU
    &WFOU
    ֎෦͔Β$VSSFOUͷ8BJUJOH4UBUFʹ౉͞ΕΔ
    8BUJOH4UBUF͔Β3VOOJOH4UBUFʹ౉͞ΕΔ
    $VSSFOU
    DMPTJOH

    View Slide

  28. DMPTFE PQFOFE
    $VSSFOU
    'MPX(SBQI%PPS
    DMPTFEεςʔτʹ଴ػ͍ͯ͠Δ
    DMPTJOH
    PQFOJOH

    View Slide

  29. DMPTFE PQFOFE
    $VSSFOU
    'MPX(SBQI%PPS
    PQFO
    PQFOΠϕϯτΛDVSSFOUͷεςʔτʹ౉͢
    DMPTJOH
    PQFOJOH

    View Slide

  30. DMPTFE PQFOFE
    $VSSFOU
    'MPX(SBQI%PPS
    PQFOJOHεςʔτʹભҠͯ͠։͘ॲཧΛ࣮ߦ͢Δ
    DMPTJOH
    PQFOJOH

    View Slide

  31. DMPTFE PQFOFE
    $VSSFOU
    'MPX(SBQI%PPS
    PQFOFEεςʔτʹભҠͯ͠଴ػ͢Δ
    DMPTJOH
    PQFOJOH

    View Slide

  32. DMPTFE PQFOFE
    $VSSFOU
    'MPX(SBQI%PPS
    DMPTF
    DMPTFΠϕϯτΛDVSSFOUͷεςʔτʹ౉͢
    DMPTJOH
    PQFOJOH

    View Slide

  33. DMPTFE PQFOFE
    $VSSFOU
    'MPX(SBQI%PPS
    DMPTJOHεςʔτʹભҠͯ͠ด͡ΔॲཧΛ࣮ߦ͢Δ
    DMPTJOH
    PQFOJOH

    View Slide

  34. DMPTFE PQFOFE
    $VSSFOU
    'MPX(SBQI%PPS
    DMPTFEεςʔτʹભҠͯ͠଴ػ͢Δ
    DMPTJOH
    PQFOJOH

    View Slide

  35. DMPTFE PQFOFE
    $VSSFOU
    'MPX(SBQI%PPS
    DMPTFEεςʔτʹભҠͯ͠଴ػ͢Δ
    DMPTJOH
    PQFOJOH
    DMPTF

    View Slide

  36. DMPTFE PQFOFE
    $VSSFOU
    'MPX(SBQI%PPS
    DMPTFEεςʔτʹભҠͯ͠଴ػ͢Δ
    DMPTJOH
    PQFOJOH

    View Slide

  37. 'MPX(SBQIͷॻ͖ํ
    ܕͷఆٛ
    ઃܭΦϒδΣΫτͷੜ੒
    εςʔτͷొ࿥
    ࣮ߦΦϒδΣΫτͷੜ੒
    ΠϕϯτΛड͚औΔ

    View Slide

  38. ܕͷఆٛ

    View Slide

  39. 'MPX(SBQI5ZQFʹద߹ͨ͠ܕΛఆٛ
    public protocol FlowGraphType {
    associatedtype WaitingState: Hashable
    associatedtype RunningState: Hashable
    associatedtype Event
    ...
    }

    View Slide

  40. class Door: FlowGraphType {
    enum WaitingState {
    case closed
    case opened
    }
    enum RunningState {
    case opening
    case closing
    }
    typealias Event = (kind: EventKind, object: Door)
    ...
    }
    'MPX(SBQI5ZQFʹద߹ͨ͠ܕΛఆٛ

    View Slide

  41. class Door: FlowGraphType {
    enum WaitingState {
    case closed
    case opened
    }
    enum RunningState {
    case opening
    case closing
    }
    typealias Event = (kind: EventKind, object: Door)
    ...
    }
    ଴ػ͢ΔεςʔτͷܕʢFOVNਪ঑ʣ
    'MPX(SBQI5ZQFʹ४ڌͨ͠ܕΛఆٛ

    View Slide

  42. class Door: FlowGraphType {
    enum WaitingState {
    case closed
    case opened
    }
    enum RunningState {
    case opening
    case closing
    }
    typealias Event = (kind: EventKind, object: Door)
    ...
    }
    ࣮ߦ͢ΔεςʔτͷܕʢFOVNਪ঑ʣ
    'MPX(SBQI5ZQFʹ४ڌͨ͠ܕΛఆٛ

    View Slide

  43. class Door: FlowGraphType {
    enum WaitingState {
    case closed
    case opened
    }
    enum RunningState {
    case opening
    case closing
    }
    typealias Event = (kind: EventKind, object: Door)
    ...
    } ड͚औΔΠϕϯτͷܕʢͳΜͰ΋ʣ
    'MPX(SBQI5ZQFʹ४ڌͨ͠ܕΛఆٛ
    enum EventKind {
    case open
    case close
    }

    View Slide

  44. ઃܭΦϒδΣΫτͷੜ੒

    View Slide

  45. let builder = FlowGraphBuilder()
    'MPX(SBQI#VJMEFSΛੜ੒

    View Slide

  46. εςʔτͷొ࿥

    View Slide

  47. builder.add(waiting: .closed) { event in
    if case .open = event.kind {
    return .run(.opening, event)
    } else {
    return .stay
    }
    }
    8BJUJOH4UBUFͷొ࿥

    View Slide

  48. builder.add(waiting: .closed) { event in
    if case .open = event.kind {
    return .run(.opening, event)
    } else {
    return .stay
    }
    }
    8BJUJOH4UBUFͷొ࿥
    ొ࿥͢Δεςʔτ໊

    View Slide

  49. builder.add(waiting: .closed) { event in
    if case .open = event.kind {
    return .run(.opening, event)
    } else {
    return .stay
    }
    }
    8BJUJOH4UBUFͷొ࿥
    ొ࿥͢ΔΫϩʔδϟ

    View Slide

  50. builder.add(waiting: .closed) { event in
    if case .open = event.kind {
    return .run(.opening, event)
    } else {
    return .stay
    }
    }
    ΠϕϯτΛड͚औΔ
    8BJUJOH4UBUFͷొ࿥

    View Slide

  51. builder.add(waiting: .closed) { event in
    if case .open = event.kind {
    return .run(.opening, event)
    } else {
    return .stay
    }
    }
    8BJUJOH4UBUFͷొ࿥
    ผͷεςʔτʹભҠ͢Δ

    View Slide

  52. builder.add(waiting: .closed) { event in
    if case .open = event.kind {
    return .run(.opening, event)
    } else {
    return .stay
    }
    }
    8BJUJOH4UBUFͷొ࿥
    return .wait(.opened)
    ผͷεςʔτʹભҠ͢Δ

    View Slide

  53. builder.add(waiting: .closed) { event in
    if case .open = event.kind {
    return .run(.opening, event)
    } else {
    return .stay
    }
    } Կ΋͠ͳ͍
    8BJUJOH4UBUFͷొ࿥

    View Slide

  54. builder.add(running: .opening) { event in
    event.object.isOpen = true
    return .wait(.opened)
    }
    3VOOJOH4UBUFͷొ࿥

    View Slide

  55. builder.add(running: .opening) { event in
    event.object.isOpen = true
    return .wait(.opened)
    }
    Կ͔ॲཧΛ͢Δ
    3VOOJOH4UBUFͷొ࿥

    View Slide

  56. builder.add(running: .opening) { event in
    event.object.isOpen = true
    return .wait(.opened)
    }
    ผͷεςʔτʹભҠ͢Δ
    3VOOJOH4UBUFͷొ࿥
    ❇3VOOJOH4UBUFʹཹ·Δ͜ͱ͸Ͱ͖ͳ͍

    View Slide

  57. ࣮ߦΦϒδΣΫτͷੜ੒

    View Slide

  58. self.graph = builder.build(initial: .closed)
    'MPX(SBQIΛੜ੒͢Δ

    View Slide

  59. self.graph = builder.build(initial: .closed)
    'MPX(SBQIΛੜ੒͢Δ
    private let graph: FlowGraph
    ϓϩύςΟ

    View Slide

  60. self.graph = builder.build(initial: .closed)
    'MPX(SBQIΛੜ੒͢Δ
    ࠷ॳʹ଴ػ͢Δεςʔτ

    View Slide

  61. Πϕϯτͷड͚औΓ

    View Slide

  62. ΠϕϯτΛड͚औΔ
    func run(_ kind: EventKind) {
    self.graph.run((kind, self))
    }

    View Slide

  63. func run(_ kind: EventKind) {
    self.graph.run((kind, self))
    }
    ΠϕϯτΛड͚औΔ
    ΠϕϯτΛ౉͢

    View Slide

  64. 'MPX(SBQI%PU$POWFSUFS

    View Slide

  65. 4PVSDF,JUUFO
    w 4PVSDF,JUΛίϚϯυϥΠϯͰ࢖͑ΔΑ͏ʹͨ͠
    ϥΠϒϥϦ
    w 4XJGUͷίʔυΛղੳͯ͠ɺߏ଄ΛऔಘͰ͖Δ
    w 4PVSDF,JUUFO'SBNFXPSLΛΠϯϙʔτ͢Ε͹ɺ
    4XJGUͷϥΠϒϥϦͱͯ͠΋࢖͑Δ

    View Slide

  66. w4USVDUVSF
    w4ZOUBY
    ղੳ͢Δػೳ

    View Slide

  67. 4USVDUVSF
    w πϦʔߏ଄Ͱղੳ͢Δ
    w DMBTT΍ؔ਺΍ม਺ͳͲͷߏ଄͕औಘͰ͖Δ
    w ίϝϯτͳͲ͸ແࢹ͞ΕΔ

    View Slide

  68. \
    LFZEJBHOPTUJD@TUBHFTPVSDFEJBHOPTUJDTUBHFTXJGUQBSTF
    LFZMFOHUI
    LFZP⒎TFU
    LFZTVCTUSVDUVSF<
    \
    LFZBDDFTTJCJMJUZTPVSDFMBOHTXJGUBDDFTTJCJMJUZJOUFSOBM
    LFZCPEZMFOHUI
    LFZCPEZP⒎TFU
    LFZFMFNFOUT<
    \
    LFZLJOETPVSDFMBOHTXJGUTUSVDUVSFFMFNUZQFSFG
    LFZMFOHUI
    LFZP⒎TFU
    ^
    >
    LFZJOIFSJUFEUZQFT<
    \
    LFZOBNF'MPX(SBQI5ZQF
    ^
    >
    LFZLJOETPVSDFMBOHTXJGUEFDMDMBTT
    LFZMFOHUI
    LFZOBNF%PPS
    LFZOBNFMFOHUI
    4USVDUVSF

    View Slide

  69. \
    LFZEJBHOPTUJD@TUBHFTPVSDFEJBHOPTUJDTUBHFT
    LFZMFOHUI
    LFZP⒎TFU
    LFZTVCTUSVDUVSF<
    \
    LFZBDDFTTJCJMJUZTPVSDFMBOHTXJGUBDDFTTJCJ
    LFZCPEZMFOHUI
    LFZCPEZP⒎TFU
    LFZFMFNFOUT<
    \
    LFZLJOETPVSDFMBOHTXJGUTUSVDUVSFFMFN
    LFZMFOHUI
    LFZP⒎TFU
    P⒎TFUͱMFOHUIͰ
    ཁૉͷจࣈྻͷҐஔ͕
    औಘͰ͖Δ

    View Slide

  70. \
    LFZEJBHOPTUJD@TUBHFTPVSDFEJBHOPTUJDTUBHFT
    LFZMFOHUI
    LFZP⒎TFU
    LFZTVCTUSVDUVSF<
    \
    LFZBDDFTTJCJMJUZTPVSDFMBOHTXJGUBDDFTTJCJ
    LFZCPEZMFOHUI
    LFZCPEZP⒎TFU
    LFZFMFNFOUT<
    \
    LFZLJOETPVSDFMBOHTXJGUTUSVDUVSFFMFN
    LFZMFOHUI
    LFZP⒎TFU
    TVCTUSVDUVSFʹࢠͷཁૉͷ഑ྻ

    View Slide

  71. LFZP⒎TFU
    LFZTVCTUSVDUVSF<
    \
    LFZBDDFTTJCJMJUZTPVSDFMBOHTXJGUBDDFTTJCJ
    LFZCPEZMFOHUI
    LFZCPEZP⒎TFU
    LFZFMFNFOUT<
    \
    LFZLJOETPVSDFMBOHTXJGUTUSVDUVSFFMFN
    LFZMFOHUI
    LFZP⒎TFU
    ^
    >
    LFZJOIFSJUFEUZQFT<
    LJOE͸ཁૉͷछྨ

    View Slide

  72. ΫϥεΛ୳͢

    View Slide

  73. // Door.swift
    //
    import FlowGraph
    // υΞͷঢ়ଶ
    class Door: FlowGraphType {
    private(set) var isOpen: Bool = false
    didSet {
    print("isOpen \(self.isOpen)")
    if let handler = self.isOpenHa
    handler(self.isOpen)
    }
    }
    }
    var isOpenHandler: ((Bool) -> Void)?

    View Slide

  74. LFZJOIFSJUFEUZQFT<
    \
    LFZOBNF'MPX(SBQI5ZQF
    ^
    >
    LFZLJOETPVSDFMBOHTXJGUEFDMDMBTT
    LFZMFOHUI
    LFZOBNF%PPS
    LFZOBNFMFOHUI
    LFZOBNFP⒎TFU
    LFZP⒎TFU
    LFZSVOUJNF@OBNF@5U$@@NBJO@@%PPS
    LFZTVCTUSVDUVSF<
    \
    LFZBDDFTTJCJMJUZTPVSDFMBOHTXJGUBDDFTTJCJM
    LJOE͕DMBTT

    View Slide

  75. LFZJOIFSJUFEUZQFT<
    \
    LFZOBNF'MPX(SBQI5ZQF
    ^
    >
    LFZLJOETPVSDFMBOHTXJGUEFDMDMBTT
    LFZMFOHUI
    LFZOBNF%PPS
    LFZOBNFMFOHUI
    LFZOBNFP⒎TFU
    LFZP⒎TFU
    LFZSVOUJNF@OBNF@5U$@@NBJO@@%PPS
    LFZTVCTUSVDUVSF<
    \
    LFZBDDFTTJCJMJUZTPVSDFMBOHTXJGUBDDFTTJCJM
    P⒎TFUͱMFOHIͰ
    ΫϥεͷҐஔΛऔಘ

    View Slide

  76. LFZJOIFSJUFEUZQFT<
    \
    LFZOBNF'MPX(SBQI5ZQF
    ^
    >
    LFZLJOETPVSDFMBOHTXJGUEFDMDMBTT
    LFZMFOHUI
    LFZOBNF%PPS
    LFZOBNFMFOHUI
    LFZOBNFP⒎TFU
    LFZP⒎TFU
    LFZSVOUJNF@OBNF@5U$@@NBJO@@%PPS
    LFZTVCTUSVDUVSF<
    \
    LFZBDDFTTJCJMJUZTPVSDFMBOHTXJGUBDDFTTJCJM
    OBNFʹDMBTTͷ໊લ

    View Slide

  77. εςʔτΛ୳͢

    View Slide

  78. init() {
    let builder = FlowGraphBuilder()
    // ด͍ͯ͡Δ
    builder.add(waiting: .closed) { event in
    if case .open = event.kind {
    return .run(.opening, event)
    } else {
    return .stay
    }
    }
    // ։͍͍ͯΔ
    builder.add(waiting: .opened) { event in
    if case .close = event.kind {
    return .run(.closing, event)
    } else {
    return .stay

    View Slide

  79. \
    LFZCPEZMFOHUI
    LFZCPEZP⒎TFU
    LFZLJOETPVSDFMBOHTXJGUFYQSDBMM
    LFZMFOHUI
    LFZOBNFCVJMEFSBEE
    LFZOBNFMFOHUI
    LFZOBNFP⒎TFU
    LFZP⒎TFU
    LFZTVCTUSVDUVSF<
    \
    LFZCPEZMFOHUI
    LFZCPEZP⒎TFU
    LFZLJOETPVSDFMBOHTXJGUFYQSBSHVNFOU
    LFZMFOHUI
    LFZOBNFXBJUJOH
    LFZOBNFMFOHUI
    FYQSDBMM͕ؔ਺ݺͼग़͠

    View Slide

  80. \
    LFZCPEZMFOHUI
    LFZCPEZP⒎TFU
    LFZLJOETPVSDFMBOHTXJGUFYQSDBMM
    LFZMFOHUI
    LFZOBNFCVJMEFSBEE
    LFZOBNFMFOHUI
    LFZOBNFP⒎TFU
    LFZP⒎TFU
    LFZTVCTUSVDUVSF<
    \
    LFZCPEZMFOHUI
    LFZCPEZP⒎TFU
    LFZLJOETPVSDFMBOHTXJGUFYQSBSHVNFOU
    LFZMFOHUI
    LFZOBNFXBJUJOH
    LFZOBNFMFOHUI
    FYQSDBMMͷOBNFʹ
    ؔ਺໊

    View Slide

  81. LFZOBNFMFOHUI
    LFZOBNFP⒎TFU
    LFZP⒎TFU
    LFZTVCTUSVDUVSF<
    \
    LFZCPEZMFOHUI
    LFZCPEZP⒎TFU
    LFZLJOETPVSDFMBOHTXJGUFYQSBSHVNFOU
    LFZMFOHUI
    LFZOBNFXBJUJOH
    LFZOBNFMFOHUI
    LFZOBNFP⒎TFU
    LFZP⒎TFU
    ^
    \
    LFZCPEZMFOHUI
    LFZCPEZP⒎TFU
    BSHVNFOU͕
    ؔ਺ͷҾ਺

    View Slide

  82. LFZOBNFMFOHUI
    LFZOBNFP⒎TFU
    LFZP⒎TFU
    LFZTVCTUSVDUVSF<
    \
    LFZCPEZMFOHUI
    LFZCPEZP⒎TFU
    LFZLJOETPVSDFMBOHTXJGUFYQSBSHVNFOU
    LFZMFOHUI
    LFZOBNFXBJUJOH
    LFZOBNFMFOHUI
    LFZOBNFP⒎TFU
    LFZP⒎TFU
    ^
    \
    LFZCPEZMFOHUI
    LFZCPEZP⒎TFU
    BSHVNFOUͷOBNFʹ
    Ҿ਺ͷϥϕϧ

    View Slide

  83. LFZOBNFMFOHUI
    LFZOBNFP⒎TFU
    LFZP⒎TFU
    LFZTVCTUSVDUVSF<
    \
    LFZCPEZMFOHUI
    LFZCPEZP⒎TFU
    LFZLJOETPVSDFMBOHTXJGUFYQSBSHVNFOU
    LFZMFOHUI
    LFZOBNFXBJUJOH
    LFZOBNFMFOHUI
    LFZOBNFP⒎TFU
    LFZP⒎TFU
    ^
    \
    LFZCPEZMFOHUI
    LFZCPEZP⒎TFU
    Ҿ਺ͷ஋ͷ෦෼͸Ґஔ͚ͩ

    View Slide

  84. init() {
    let builder = FlowGraphBuilder()
    // ด͍ͯ͡Δ
    builder.add(waiting: .closed) { event in
    if case .open = event.kind {
    return .run(.opening, event)
    } else {
    return .stay
    }
    }
    // ։͍͍ͯΔ
    builder.add(waiting: .opened) { event in
    if case .close = event.kind {
    return .run(.closing, event)
    } else {
    return .stay
    SFUVSOͷҐஔ͸Θ͔Βͳ͍

    View Slide

  85. 4ZOUBY 4ZOUBY.BQ

    View Slide

  86. {type:comment offset:0, length:3, content:'//
    '},
    {type:comment offset:3, length:15, content:'// Door.swift
    '},
    {type:comment offset:18, length:3, content:'//
    '},
    {type:keyword offset:22, length:6, content:'import'},
    {type:identifier offset:29, length:9, content:'FlowGraph'},
    {type:comment offset:40, length:19, content:'// υΞͷঢ়ଶ
    '},
    {type:keyword offset:59, length:5, content:'class'},
    {type:identifier offset:65, length:4, content:'Door'},
    {type:typeidentifier offset:71, length:13, content:'FlowGraphType'},
    {type:attributeBuiltin offset:91, length:12, content:'private(set)'},
    {type:keyword offset:104, length:3, content:'var'},
    {type:identifier offset:108, length:6, content:'isOpen'},
    {type:typeidentifier offset:116, length:4, content:'Bool'},
    {type:keyword offset:123, length:5, content:'false'},
    {type:keyword offset:139, length:6, content:'didSet'},
    {type:identifier offset:160, length:5, content:'print'},
    {type:string offset:166, length:8, content:'"isOpen '},
    {type:stringInterpolationAnchor offset:175, length:1, content:'('},
    {type:keyword offset:176, length:4, content:'self'},
    {type:identifier offset:181, length:6, content:'isOpen'},
    {type:stringInterpolationAnchor offset:187, length:1, content:')'},

    View Slide

  87. {type:keyword
    offset:59,
    length:5,
    content:'class'}

    View Slide

  88. {type:identifier
    offset:65,
    length:4,
    content:'Door'}

    View Slide

  89. {type:comment
    offset:40,
    length:19,
    content:'// υΞͷঢ়ଶ
    '}

    View Slide

  90. init() {
    let builder = FlowGraphBuilder()
    // ด͍ͯ͡Δ
    builder.add(waiting: .closed) { event in
    if case .open = event.kind {
    return .run(.opening, event)
    } else {
    return .stay
    }
    }
    // ։͍͍ͯΔ
    builder.add(waiting: .opened) { event in
    if case .close = event.kind {
    return .run(.closing, event)
    } else {
    return .stay
    ؔ਺ͷCPEZ෦෼

    View Slide

  91. '},
    {type:identifier offset:800, length:7, content:'builder'},
    {type:identifier offset:808, length:3, content:'add'},
    {type:identifier offset:812, length:7, content:'waiting'},
    {type:identifier offset:822, length:6, content:'closed'},
    {type:identifier offset:832, length:5, content:'event'},
    {type:keyword offset:838, length:2, content:'in'},
    {type:keyword offset:853, length:2, content:'if'},
    {type:keyword offset:856, length:4, content:'case'},
    {type:identifier offset:862, length:4, content:'open'},
    {type:identifier offset:869, length:5, content:'event'},
    {type:identifier offset:875, length:4, content:'kind'},
    {type:keyword offset:898, length:6, content:'return'},
    {type:identifier offset:906, length:3, content:'run'},
    {type:identifier offset:911, length:7, content:'opening'},
    {type:identifier offset:920, length:5, content:'event'},
    {type:keyword offset:941, length:4, content:'else'},
    {type:keyword offset:964, length:6, content:'return'},
    {type:identifier offset:972, length:4, content:'stay'},
    {type:comment offset:1018, length:19, content:'// ։͍͍ͯΔ
    '},
    {type:identifier offset:1045, length:7, content:'builder'},
    {type:identifier offset:1053, length:3, content:'add'},
    {type:identifier offset:1057, length:7, content:'waiting'},
    {type:identifier offset:1067, length:6, content:'opened'},

    View Slide

  92. '},
    {type:identifier offset:800, length:7, content:'builder'},
    {type:identifier offset:808, length:3, content:'add'},
    {type:identifier offset:812, length:7, content:'waiting'},
    {type:identifier offset:822, length:6, content:'closed'},
    {type:identifier offset:832, length:5, content:'event'},
    {type:keyword offset:838, length:2, content:'in'},
    {type:keyword offset:853, length:2, content:'if'},
    {type:keyword offset:856, length:4, content:'case'},
    {type:identifier offset:862, length:4, content:'open'},
    {type:identifier offset:869, length:5, content:'event'},
    {type:identifier offset:875, length:4, content:'kind'},
    {type:keyword offset:898, length:6, content:'return'},
    {type:identifier offset:906, length:3, content:'run'},
    {type:identifier offset:911, length:7, content:'opening'},
    {type:identifier offset:920, length:5, content:'event'},
    {type:keyword offset:941, length:4, content:'else'},
    {type:keyword offset:964, length:6, content:'return'},
    {type:identifier offset:972, length:4, content:'stay'},
    {type:comment offset:1018, length:19, content:'// ։͍͍ͯΔ
    '},
    {type:identifier offset:1045, length:7, content:'builder'},
    {type:identifier offset:1053, length:3, content:'add'},
    {type:identifier offset:1057, length:7, content:'waiting'},
    {type:identifier offset:1067, length:6, content:'opened'},

    View Slide

  93. εςʔτͷ5PLFOΛղੳ͢Δ

    View Slide

  94. waiting
    closed
    event
    in
    if
    case
    open
    event
    kind
    return
    run
    opening
    event
    else
    return
    stay
    ಄͔Βॱ൪ʹݟ͍ͯ͘

    View Slide

  95. waiting
    closed
    event
    in
    if
    case
    open
    event
    kind
    return
    run
    opening
    event
    else
    return
    stay
    XBJUJOH͔
    SVOOJOH
    ͳΒʜ
    XBJUJOH

    View Slide

  96. waiting
    closed
    event
    in
    if
    case
    open
    event
    kind
    return
    run
    opening
    event
    else
    return
    stay
    ࣍͸
    εςʔτ໊
    XBJUJOH
    DMPTFE

    View Slide

  97. waiting
    closed
    event
    in
    if
    case
    open
    event
    kind
    return
    run
    opening
    event
    else
    return
    stay
    JOͷޙ͔Β
    Ϋϩʔδϟ
    XBJUJOH
    DMPTFE

    View Slide

  98. waiting
    closed
    event
    in
    if
    case
    open
    event
    kind
    return
    run
    opening
    event
    else
    return
    stay
    SFUVSOΛ୳͢
    XBJUJOH
    DMPTFE

    View Slide

  99. waiting
    closed
    event
    in
    if
    case
    open
    event
    kind
    return
    run
    opening
    event
    else
    return
    stay
    SVO͔
    XBJUͳΒʜ
    XBJUJOH
    DMPTFE

    View Slide

  100. waiting
    closed
    event
    in
    if
    case
    open
    event
    kind
    return
    run
    opening
    event
    else
    return
    stay
    ਐΉઌͷ
    εςʔτ໊
    XBJUJOH
    DMPTFE
    PQFOJOH

    View Slide

  101. waiting
    closed
    event
    in
    if
    case
    open
    event
    kind
    return
    run
    opening
    event
    else
    return
    stay
    SFUVSOΛ୳͢
    XBJUJOH
    DMPTFE
    PQFOJOH

    View Slide

  102. waiting
    closed
    event
    in
    if
    case
    open
    event
    kind
    return
    run
    opening
    event
    else
    return
    stay TUBZͳΒແࢹ
    XBJUJOH
    DMPTFE
    PQFOJOH

    View Slide

  103. εςʔτղੳͷ
    ঢ়ଶભҠਤ

    View Slide

  104. %PU

    View Slide

  105. digraph {
    graph [label = "Door", labelloc = "t", labeljust = "l",
    fontcolor = "#333333", rankdir = "TB",
    fontname = "Osaka-Mono", fontsize = "12",
    charset = "UTF-8"]
    node [fontcolor = "#333333", fillcolor = "#F9F9F9",
    fontname = "Osaka-Mono", style = "solid,filled",
    fontsize = "10", color = "#CCCCCC"]
    edge [fontcolor = "#333333", fontname = "Osaka-Mono",
    fontsize = "9", color = "#AAAAAA"]
    opened [shape = "record", label = "{opened|։͍͍ͯΔ}",
    color = "#BBBBBB"]
    closing [shape = "record", label = "{closing|ด͡Δ}",
    color = "#40C5EE"]
    closed [shape = "record", label = "{closed|ด͍ͯ͡Δ}",
    color = "#00D54B"]
    opening [shape = "record", label = "{opening|։͘}",
    color = "#40C5EE"]
    "opened" -> "closing" [style = "solid", color = "#99DEF3"]
    "closing" -> "closed" [style = "dashed", color = "#AAAAAA"]
    "closed" -> "opening" [style = "solid", color = "#99DEF3"]
    "opening" -> "opened" [style = "dashed", color = "#AAAAAA"]
    }
    %PPSEPU

    View Slide

  106. digraph {
    graph [label = "Door", labelloc = "t
    fontcolor = "#333333", rankdi
    fontname = "Osaka-Mono", font
    charset = "UTF-8"]
    node [fontcolor = "#333333", fillcol
    fontname = "Osaka-Mono", style
    fontsize = "10", color = "#CCC
    edge [fontcolor = "#333333", fontnam
    fontsize = "9", color = "#AAAA
    opened [shape = "record", label = "{
    EJHSBQI͸༗޲άϥϑ
    %PPSEPU

    View Slide

  107. charset = "UTF-8"]
    node [fontcolor = "#333333", fillcolor = "
    fontname = "Osaka-Mono", style = "so
    fontsize = "10", color = "#CCCCCC"]
    edge [fontcolor = "#333333", fontname = "O
    fontsize = "9", color = "#AAAAAA"]
    opened [shape = "record",
    label = "{opened|։͍͍ͯΔ}",
    color = "#BBBBBB"]
    closing [shape = "record", label = "{closi
    color = "#40C5EE"]
    closed [shape = "record", label = "{closed
    color = "#00D54B"]
    opening [shape = "record", label = "{openi
    color = "#40C5EE"]
    ϊʔυͷ໊લ
    ϊʔυ

    View Slide

  108. charset = "UTF-8"]
    node [fontcolor = "#333333", fillcolor = "
    fontname = "Osaka-Mono", style = "so
    fontsize = "10", color = "#CCCCCC"]
    edge [fontcolor = "#333333", fontname = "O
    fontsize = "9", color = "#AAAAAA"]
    opened [shape = "record",
    label = "{opened|։͍͍ͯΔ}",
    color = "#BBBBBB"]
    closing [shape = "record", label = "{closi
    color = "#40C5EE"]
    closed [shape = "record", label = "{closed
    color = "#00D54B"]
    opening [shape = "record", label = "{openi
    color = "#40C5EE"]
    <>ͷதʹදࣔ͞ΕΔத਎
    ϊʔυ

    View Slide

  109. closing [shape = "record", label = "{closing
    color = "#40C5EE"]
    closed [shape = "record", label = "{closed|ด
    color = "#00D54B"]
    opening [shape = "record", label = "{opening
    color = "#40C5EE"]
    "opened" -> "closing" [style = "solid",
    color = "#99DEF3"]
    "closing" -> "closed" [style = "dashed", col
    "closed" -> "opening" [style = "solid", colo
    "opening" -> "opened" [style = "dashed", col
    }
    Τοδ
    ͰϊʔυΛͭͳ͛Δ

    View Slide

  110. 'MPX(SBQI
    IUUQTHJUIVCDPNPCKFDUJWFBVEJP4XJGU'MPX(SBQI
    'MPX(SBQI%PU$POWFSUFS
    IUUQTHJUIVCDPNPCKFDUJWFBVEJP'MPX(SBQI%PU$POWFSUFS
    4PVSDF,JUUFO
    (SBQIWJ[
    IUUQTHJUIVCDPNKQTJN4PVSDF,JUUFO
    IUUQTXXXHSBQIWJ[PSH
    ຊ೔ͷαϯϓϧ
    IUUQTHJUIVCDPNPCKFDUJWFBVEJPJ04%$

    View Slide