$30 off During Our Annual Pro Sale. View Details »

Rubyパターンマッチに闇の力が備わり最強に見える

 Rubyパターンマッチに闇の力が備わり最強に見える

Burikaigi2020の発表資料です

kokuyouwind

February 01, 2020
Tweet

More Decks by kokuyouwind

Other Decks in Programming

Transcript

  1. Ruby
    パターンマッチに
    闇の⼒が備わり最強に⾒える
    283
    プロ/346
    プロ アイドルプロデューサー
    黒曜
    (@kokuyouwind)

    View Slide

  2. ⾃⼰紹介
    黒曜(@kokuyouwind)
    アイマスプロデューサー
    (283/346
    兼務)
    担当アイドル
    櫻⽊真乃(283
    プロ)
    ⽩菊ほたる(346
    プロ)
    副業でWeb
    エンジニア@Misoca

    View Slide

  3. 担当アイドル紹介-
    櫻⽊真乃
    ほんわかした癒やし系アイドル。
    illumination STARS
    という
    3
    ⼈ユニットのセンター。
    ⼼優しい性格だが、
    センターという役割に悩む
    責任感の強い⼀⾯も。
    イルミネはエモの塊

    View Slide

  4. 担当アイドル紹介-
    ⽩菊ほたる
    所属事務所が3
    連続で倒産した
    不運な少⼥。思考が後ろ向き。
    それでもアイドルを⽬指すのは、
    不幸を撒き散らした⾃分でも
    誰かを幸せにしたいから。
    かこほたは運命

    View Slide

  5. Ruby

    パターンマッチの
    話をします

    View Slide

  6. Ruby
    のパターンマッチ
    条件分岐とデータ分解を兼ねる機能
    Ruby 2.7.0
    で実験的に導⼊された
    関数型プログラミング⾔語からの輸⼊
    Ruby
    らしさを壊さないように仕様策定
    に詳しい話がある
    dack typing
    などに配慮して設計
    n
    ⽉刊ラムダノート

    View Slide

  7. Ruby
    らしさ
    instance_eval
    TracePoint
    Binding
    Flip Flop
    prepend

    View Slide

  8. Ruby
    パターンマッチに
    闇の⼒が備わり最強に⾒える

    View Slide

  9. アジェンダ
    Ruby
    パターンマッチの概要
    闇の⼒で強化する
    闇の⼒でできることを考える
    まとめ

    View Slide

  10. 全サンプルコードは以下リポジトリにあります
    https://github.com/kokuyouwind/pattern_match_demo
    $ git clone https://github.com/kokuyouwind/pattern_mat
    $ cd pattern_match_demo
    $ bundle install
    $ bundle exec ruby -W:no-experimental src/01_array.rb
    # or
    $ export RUBYOPT=-W:no-experimental
    $ bundle exec ruby src/01_array.rb
    1
    2
    3
    4
    5
    6
    7
    8

    View Slide

  11. アジェンダ
    Ruby
    パターンマッチの概要
    闇の⼒で強化する
    闇の⼒でできることを考える
    まとめ

    View Slide

  12. パターンマッチ
    case
    ⽂の分岐で in pattern
    を使える
    pattern
    部分にはいろんなパターンを
    組み合わせて書ける
    Variable Pattern
    Array Pattern
    Hash Pattern
    etc

    View Slide

  13. 正確なパターン定義は

    ⾒よう!
    辻元さんのスライド

    View Slide

  14. パターン概要
    Array Pattern

    View Slide

  15. Array Pattern
    #
    配列の要素ごとにパターンマッチできる
    case [1, 2, 3]
    in [2, _, _]
    fail #
    マッチしない
    in [1, x, y]
    puts "x: #{x}, y: #{y}" # => x: 2, y: 3
    end
    1
    2
    3
    4
    5
    6
    7
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/01_array.rb

    View Slide

  16. Array Pattern
    # *
    を使って残りとマッチできる
    case [1, 2, 3]
    in [x, *y]
    puts "x: #{x}, y: #{y}" # => x: 1, y: [2,
    end
    # 1
    ⾏でin
    を使ってパターンマッチできる
    [1, 2, 3] in [x, _, _]
    puts "x: #{x}" # => x: 1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/01_array.rb

    View Slide

  17. Array Pattern
    # destruct
    を定義してればなんでもマッチできる
    class Tester
    def self.deconstruct
    [1, 2, 3]
    end
    end
    case Tester
    in [_, x, _]
    puts "x: #{x}" # => x: 2
    end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/01_array.rb

    View Slide

  18. パターン概要
    Hash Pattern

    View Slide

  19. Hash Pattern
    #
    ハッシュのキーごとにパターンマッチできる
    case { first: "Hotaru", last: "Shiragiku" }
    in { first: "Kako", last: _ }
    fail #
    マッチしない
    in { first: "Hotaru", last: name }
    puts "name: #{name}" # => name: Shiragiku
    end
    1
    2
    3
    4
    5
    6
    7
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/02_hash.rb

    View Slide

  20. Hash Pattern
    # 1
    ⾏でin
    を使ってマッチできる
    # **
    を使って残りとマッチできる
    { first: "Hotaru", last: "Shiragiku" } \
    in { first: first, **rest }
    puts "first: #{first}, rest: #{rest}"
    # => first: Hotaru, rest: {:last=>"Shiragik
    1
    2
    3
    4
    5
    6
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/02_hash.rb

    View Slide

  21. Hash Pattern
    # deconstruct_keys
    を定義すれば何でもマッチできる
    #
    引数には「マッチしようとしたキー名」が配列で渡る
    class Tester
    def self.deconstruct_keys(_)
    { first: "Hotaru", last: "Shiragiku" }
    end
    end
    case Tester
    in { first: "Hotaru", last: name }
    puts "name: #{name}" # => name: Shiragiku
    end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/02_hash.rb

    View Slide

  22. パターン概要
    Constant Pattern + α

    View Slide

  23. Constant Pattern
    #
    定数を指定してマッチできる
    case 1
    in String
    fail #
    マッチしない
    in Integer
    puts "1 is Integer"
    end
    1
    2
    3
    4
    5
    6
    7
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/03_constant.rb

    View Slide

  24. Array Pattern with Const.
    #
    定数と配列を合わせて指定できる
    Point = Struct.new(:x, :y)
    case Point.new(1, 2)
    in Point[x, y]
    puts "x: #{x}, y: #{y}" # => x: 1, y: 2
    end
    1
    2
    3
    4
    5
    6
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/03_constant.rb

    View Slide

  25. Hash Pattern with Const.
    #
    定数とハッシュを合わせて指定できる
    case Point.new(3, 4)
    in Point(x: x, y: y)
    puts "x: #{x}, y: #{y}" # => x: 3, y: 4
    end
    1
    2
    3
    4
    5
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/03_constant.rb

    View Slide

  26. Constant Pattern
    # ===
    を定義すればマッチ条件を変えられる
    class Tester
    def self.===(other)
    other.nil?
    end
    end
    # case
    ではなく in (
    パターン側)
    が使われる
    case nil
    in Tester
    puts "nil matched"
    end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/03_constant.rb

    View Slide

  27. パターンマッチ
    実⽤例

    View Slide

  28. 実⽤例: JSON Response
    response = {
    status: "ok",
    body: {
    id: 1,
    url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347"
    user: {
    login: "octocat",
    id: 2,
    type: "User",
    site_admin: false
    },
    assignee: {
    login: "kokuyou",
    id: 3,
    type: "User",
    site_admin: true
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/04_example_response.rb

    View Slide

  29. 実⽤例: JSON Response
    response = {
    status: "ok",
    body: {
    id: 1,
    url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347"
    user: {
    login: "octocat",
    id: 2,
    type: "User",
    site_admin: false
    },
    assignee: {
    login: "kokuyou",
    id: 3,
    type: "User",
    site_admin: true
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/04_example_response.rb

    View Slide

  30. 実⽤例: JSON Response
    #
    全体のid
    と、user
    とassignee
    のlogin name
    を取り出したい
    # dig
    を使う場合
    p [response.dig(:body, :id),
    response.dig(:body, :user, :login),
    response.dig(:body, :assignee, :login)]
    #
    パターンマッチを使う場合
    response in {
    body: {
    id: id,
    user: { login: name1 },
    assignee: { login: name2 }
    }
    }
    p [id, name1, name2]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/04_example_response.rb

    View Slide

  31. 実⽤例: AST
    tree = RubyVM::AbstractSyntaxTree.parse('1 + 2')
    # tree
    は以下のようなオブジェクトになる
    RubyVM::AbstractSyntaxTree::NODE(type: :SCOPE, children:
    ...,
    RubyVM::AbstractSyntaxTree::NODE(type: OPCALL, children
    RubyVM::AbstractSyntaxTree::NODE(type: LIT, children:
    :+,
    RubyVM::AbstractSyntaxTree::NODE(type: LIST, children
    RubyVM::AbstractSyntaxTree::NODE(type: LIT, childre
    nil
    ])
    ])
    ])
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/05_ast.rb

    View Slide

  32. 実⽤例: AST
    def print_tree(node, indent = 0)
    print '| ' * indent
    case [node&.type, node&.children]
    in [:SCOPE, [_, _, n1]]
    puts 'scope'; print_tree(n1, indent + 1)
    in [:OPCALL, [n1, op, n2]]
    puts op.to_s; print_tree(n1, indent + 1); print_tree(n2,
    in [:LIST, [h, t]]
    puts 'cons'; print_tree(h, indent + 1); print_tree(t, ind
    in [:LIT, [lit]]
    puts lit.to_s
    in [nil, _]
    puts 'nil'
    end
    end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/05_ast.rb

    View Slide

  33. 実⽤例: AST
    print_tree(RubyVM::AbstractSyntaxTree.parse('
    # scope
    # | +
    # | | 1
    # | | cons
    # | | | 2
    # | | | nil
    1
    2
    3
    4
    5
    6
    7
    8
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/05_ast.rb

    View Slide

  34. 実⽤例: AST
    print_tree(RubyVM::AbstractSyntaxTree.parse('1 + 2 * 3 -
    # scope
    # | -
    # | | +
    # | | | 1
    # | | | cons
    # | | | | *
    # | | | | | 2
    # | | | | | cons
    # | | | | | | 3
    # | | | | | | nil
    # | | | | nil
    # | | cons
    # | | | 4
    # | | | nil
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/05_ast.rb

    View Slide

  35. アジェンダ
    Ruby
    パターンマッチの概要
    闇の⼒で強化する
    闇の⼒でできることを考える
    まとめ

    View Slide

  36. Active Pattern in F#
    //
    マッチ対象と独⽴してパターンを定義
    let (|Even|Odd|) input =
    if input % 2 = 0 then Even else Odd
    //
    パターンマッチに使える
    let TestNumber input =
    match input with
    | Even -> printfn "%d is even" input
    | Odd -> printfn "%d is odd" input
    TestNumber 7 // 7 is odd
    TestNumber 11 // 11 is odd
    TestNumber 32 // 32 is even
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    https://docs.microsoft.com/ja-jp/dotnet/fsharp/language-reference/active-patterns

    View Slide

  37. やりたい!!!!

    View Slide

  38. 作った!!!!!!!

    View Slide

  39. Parity Check with Active Pattern
    module Parity
    extend ActivePattern::Context[Integer]
    Even = pattern { self % 2 == 0 }
    Odd = pattern { self % 2 != 0 }
    end
    def test_number(input)
    case input
    in Parity::Even; puts "#{input} is even"
    in Parity::Odd; puts "#{input} is odd"
    end
    end
    test_number 7 # => 7 is odd
    test_number 11 # => 11 is odd
    test_number 32 # => 32 is even
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/10_active_pattern_examples.rb

    View Slide

  40. これだけなら
    ===
    を定義すればできる

    View Slide

  41. Active Pattern in F# (2)
    type Point = { X: float; Y: float; }
    let (|Polar|) (p : Point) =
    ( sqrt <| p.X ** 2. + p.Y ** 2.
    , Math.Atan2(p.Y, p.X)
    )
    let printPolar (p : Point) =
    match p with
    | Polar(r, theta) -> printf "(%f, %f)" r
    let point = { X = 3.0; Y = 4.0; }
    printPolar(point) // (5.000000, 0.9272952)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    View Slide

  42. Ruby
    でもこうしたい(
    願望)
    Point = Struct.new(:x, :y)
    Polar = #
    なんらかの定義
    point = Point.new(3, 4)
    point in Polar[r, theta]
    puts "Polar: (#{r}, #{theta})"
    #
    しかしここで呼ばれるのは
    # 1. Polar.===(point)
    # 2. point.deconstruct (Point#deconstruct)
    #
    の2

    # Polar
    をどう定義してもPoint#deconstruct
    は変わらな
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    View Slide


  43. View Slide

  44. こうすればできる(
    闇)
    # 1. ===
    で作った配列をグローバル変数に⼊れる
    Polar = Module.new do
    def self.===(point)
    $TMP = [Math.sqrt(point.x ** 2 + point.y **
    Math.atan2(point.y, point.x)]
    end
    # 2. deconstruct
    をprepend
    で書き換えて
    #
    グローバル変数から返す
    Point.prepend(Module.new do
    def deconstruct
    $TMP || super
    end
    end)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    View Slide

  45. Coordinates with Active Pattern
    module Coordinates
    extend ActivePattern::Context[Point]
    Cartesian = pattern { [x, y] }
    Polar = pattern { [Math.sqrt(x ** 2 + y ** 2), Math.atan
    end
    point = Point.new(3, 4)
    point in Coordinates::Cartesian[x, y]
    puts "Catesian: (#{x}, #{y})" #=> (3, 4)
    point in Coordinates::Polar[r, theta]
    puts "Polar: (#{r}, #{theta})" #=> (5.0, 0.927295218001612
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/10_active_pattern_examples.rb

    View Slide

  46. Active Pattern gem
    F#
    のActive Pattern
    っぽいものを書ける
    Const = pattern { ... }
    を連ねる
    pattern
    で返す値によって挙動が変わる
    true/false
    を返すと定数マッチングのみ
    Array
    を返すとArray Pattern
    になる
    Hash
    を返すとHash Pattern
    になる
    https://rubygems.org/gems/active_pattern

    View Slide

  47. アジェンダ
    Ruby
    パターンマッチの概要
    闇の⼒で強化する
    闇の⼒でできることを考える
    まとめ

    View Slide

  48. JSON
    レスポンスの分解

    View Slide

  49. JSON
    レスポンスの分解
    # status
    でok
    とng
    を返すAPI
    ok_response = {
    status: "ok",
    body: {
    id: 1,
    # ...
    }
    }
    ng_response = {
    status: "ng",
    message: "Oops, something went wrong!"
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/11_active_pattern_response.rb

    View Slide

  50. JSON
    レスポンスの分解
    module Response
    extend ActivePattern::Context[Hash]
    OK = pattern { self[:status] == 'ok' && [self[:body]] }
    NG = pattern { self[:status] == 'ng' && [self[:message]] }
    end
    def print_response(response)
    case response
    in Response::OK[body]
    puts 'OK! body: ' + body.to_s
    in Response::NG[message]
    puts 'NG! message: ' + message
    end
    end
    print_response(ok_response)
    print_response(ng_response)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/11_active_pattern_response.rb

    View Slide

  51. JSON
    レスポンスの分解
    # body
    からowner
    とassignee
    のlogin name
    だけ取り出したい
    module PullRequest
    extend ActivePattern::Context[Hash]
    Users = pattern { {
    owner: dig(:body, :user, :login),
    assignee: dig(:body, :assignee, :login) }
    }
    end
    ok_response in PullRequest::Users(owner: owner, assignee:
    puts "owner: #{owner}, assignee: #{assignee}"
    #=> owner: octocat, assignee: kokuyou
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/11_active_pattern_response.rb

    View Slide

  52. URL
    を振り分け

    View Slide

  53. URL
    を振り分け
    module Route
    extend ActivePattern::Context[String]
    Root = pattern { self == '/' }
    Users = pattern { self == '/users/' }
    User = pattern {
    %r|^/users/([0-9]+)/$|.match(self)&.captures
    }
    UserPosts = pattern {
    %r|^/users/([0-9]+)/posts/$|.match(self)&.captures
    }
    UserPost = pattern {
    %r|^/users/([0-9]+)/posts/([0-9]+)/$|.match(self)&.ca
    }
    end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/14_active_pattern_routes.rb

    View Slide

  54. URL
    を振り分け
    def parse_route(path)
    case path
    in Route::Root; puts 'root path'
    in Route::Users; puts 'users path'
    in Route::User[uid]; puts "user path(user_id: #{uid})"
    in Route::UserPosts[uid]; puts "user posts path(user_id: #{
    in Route::UserPost[uid, pid]
    puts "user post path(user_id: #{uid}, post_id: #{pid})"
    end
    end
    parse_route('/') #=> root path
    parse_route('/users/') #=> users path
    parse_route('/users/765/') #=> user path(user_id: 765)
    parse_route('/users/765/posts/') #=> user posts path(user_id:
    parse_route('/users/765/posts/315/')
    #=> user post path(user_id: 765, post_id: 315)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/14_active_pattern_routes.rb

    View Slide

  55. 抽象構⽂⽊の実⾏

    View Slide

  56. 抽象構⽂⽊の実⾏
    module Node
    extend ActivePattern::Context[RubyVM::AbstractSyntaxTre
    Scope = pattern { type == :SCOPE && children }
    OpCall = pattern { type == :OPCALL && children }
    List = pattern { type == :LIST && children }
    Literal = pattern { type == :LIT && children }
    PlusOp = pattern { self in OpCall(x, :+, List(y, nil));
    MinusOp = pattern { self in OpCall(x, :-, List(y, nil))
    MulOp = pattern { self in OpCall(x, :*, List(y, nil));
    DivOp = pattern { self in OpCall(x, :/, List(y, nil));
    end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/13_active_pattern_eval.rb

    View Slide

  57. 抽象構⽂⽊の実⾏
    def eval_tree(tree)
    case tree
    in Node::Scope[_, _, n1]
    eval_tree(n1)
    in Node::Literal[n]
    n
    in Node::PlusOp[l, r]
    eval_tree(l) + eval_tree(r)
    in Node::MinusOp[l, r]
    eval_tree(l) - eval_tree(r)
    in Node::MulOp[l, r]
    eval_tree(l) * eval_tree(r)
    in Node::DivOp[l, r]
    eval_tree(l) / eval_tree(r)
    end
    end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/13_active_pattern_eval.rb

    View Slide

  58. 抽象構⽂⽊の実⾏
    puts eval_tree(RubyVM::AbstractSyntaxTree.parse('1 + 2
    # => 3
    puts eval_tree(
    RubyVM::AbstractSyntaxTree.parse('1 + 2 * 3 - 4 / 2'
    # => 5
    1
    2
    3
    4
    5
    6
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/13_active_pattern_eval.rb

    View Slide

  59. Presenter(
    闇)

    View Slide

  60. Presenter(
    闇)
    Video = Struct.new(:type, :status)
    module Presenter
    extend ActivePattern::Context[Video]
    Type = pattern do
    case self.type
    in :official; ['
    公式']
    in :user; ['
    ユーザ']
    end
    end
    # ...
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/15_active_pattern_presenter.rb

    View Slide

  61. Presenter(
    闇)
    # ...
    Status = pattern do
    case self.status
    in :prepare; ['
    準備中']
    in :onair; ['
    放送中']
    in :closed; ['
    放送済み']
    end
    end
    All = pattern {
    self in Type[type]; self in Status[status];
    { type: type, status: status }
    }
    end
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/15_active_pattern_presenter.rb

    View Slide

  62. Presenter(
    闇)
    v1 = Video.new(:official, :prepare)
    v1 in Presenter::Type[type]
    v1 in Presenter::Status[status]
    puts "#{type}
    番組 #{status}" #=>
    公式番組 準備中
    v2 = Video.new(:user, :onair)
    v2 in Presenter::All(type: type, status: status)
    puts "#{type}
    番組 #{status}" #=>
    ユーザ番組 放送中
    1
    2
    3
    4
    5
    6
    7
    8
    9
    https://github.com/kokuyouwind/pattern_match_demo/blob/master/src/15_active_pattern_presenter.rb

    View Slide

  63. アジェンダ
    Ruby
    パターンマッチの概要
    闇の⼒で強化する
    闇の⼒でできることを考える
    まとめ

    View Slide

  64. まとめ
    楽しい!!!!!!!!!!
    割と可能性を感じる
    複雑なパターンや定数を閉じ込められる
    データの解釈を外から与えられる

    View Slide

  65. 今後の展望
    include Context[XXX]
    の部分が
    Nominal
    になっていて微妙
    今の戦略だとprepend
    する対象が要る
    case v in C[x, y]
    みたいに書いたときに、
    C.deconstruct(v)
    が呼ばれるようにしたい
    TracePoint
    でなんとかなる?
    C
    コード書き換えないとだめかも

    View Slide