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

Pattern Matching in Ruby

k_tsj
September 15, 2012

Pattern Matching in Ruby

k_tsj

September 15, 2012
Tweet

More Decks by k_tsj

Other Decks in Programming

Transcript

  1. Pattern Matching in Ruby
    Kazuki Tsujimoto
    Nomura Research Institute, Ltd.

    View Slide

  2. 自己紹介
    • @k_tsj
    • 好きな言語:
    Ruby/Scheme/Scala
    • CRubyコミッタ
    Self introduction
    Favorite languages:
    A CRuby committer

    View Slide

  3. Ruby 2.0
    2013/2/24
    リリース予定
    will be released

    View Slide

  4. Ruby 2.0の位置づけ
    • まつもとさん曰く(2007)
    http://www.rubyist.net/~matz/slides/kobe07/index.html (Ruby 1.9を語る)
    Matz said
    Carrot
    Position of Ruby 2.0

    View Slide

  5. 新しい人参が必要
    • Multiple VM
    • JIT
    • 世代別/並列GC
    • …
    • パターンマッチ
    We need a new carrot
    Generational/Parallel GC
    Pattern matching

    View Slide

  6. パターンマッチとは
    What is pattern matching

    View Slide

  7. 辞書的定義
    • データを検索する場合に、特
    定のパターンが出現するかど
    うか、またどこに出現するか
    を特定する手法(Wikipedia)
    Dictionary definition
    Pattern matching is the act of checking a
    perceived sequence of tokens for the presence
    of the constituents of some pattern

    View Slide

  8. ?

    View Slide

  9. 多重代入
    a, (b, c) = [1, [2, 3]]
    Multiple assignment

    View Slide

  10. パターンマッチ
    Array(1, Array(2, 3)) match {
    case Array(a, Array(b, c)) =>
    ...
    }
    Pattern matching

    View Slide

  11. 比較
    a, (b, c) = [1, [2, 3]]
    Array(1, Array(2, 3)) match {
    case Array(a, Array(b, c)) =>
    ...
    }
    Comparing
    多重代入
    Multiple assignment
    パターンマッチ
    Pattern matching

    View Slide

  12. 多重代入の問題点
    1. Arrayに限定される
    Problems of multiple assignment
    Array only

    View Slide

  13. 多重代入の問題点
    a, (b, c), d = [1, [2, 3]]
    d #=> nil
    Problems of multiple assignment
    2. 個数の確認等ができない
    Can not check number of items,etc

    View Slide

  14. 多重代入の問題点
    a, (b, c) = [1, [2, 3]]
    これが欲しい
    Problems of multiple assignment
    Need it
    3. 途中の値が代入できない
    Can not assign nonterminal value

    View Slide

  15. 多重代入の問題点
    1. Arrayに限定される
    2. 個数の確認等ができない
    3. 途中の式を代入できない
    分解機能が弱い
    照合機能がない
    代入機能が弱い
    Lack of deconstructuring mechanism
    No matching mechanism
    Lack of assignment mechanism
    Problems of multiple assignment

    View Slide

  16. パターンマッチとは
    (多重代入 + α) + case
    分解 + 代入 照合
    Deconstructuring Assignment Matching
    Multiple assignment
    What is pattern matching

    View Slide

  17. 他言語のパターンマッチ
    Language Support Type Paradigm
    Python Dynamic OOP
    Scheme
    (Library)
    Dynamic FP
    Java Static OOP
    Scala Static OOP+FP
    Haskell Static FP
    F# Static FP
    (C) 2012 Yusuke Kamiyamane. All rights reserved. / Fugue Icons
    Pattern matching in other languages
    OOP: オブジェクト指向プログラミング
    FP: 関数型プログラミング

    View Slide

  18. Scalaにおける
    パターンマッチ
    Pattern matching in Scala

    View Slide

  19. 基本的な使い方
    Array(1, Array(2, 3)) match {
    case Array(a, Array(b, c)) =>
    Array(a, b, c)
    case _ => null
    }
    // => Array(1, 2, 3)
    Basic usage

    View Slide

  20. 分解
    • ArrayをArrayとして
    Array(1, Array(2, 3)) match {
    case Array(a, Array(b, c)) => ...
    }
    Deconstructuring
    Array as Array

    View Slide

  21. 分解
    • ListをListとして
    List(1, List(2, 3)) match {
    case List(a, List(b, c)) => ...
    }
    Deconstructuring
    List as List

    View Slide

  22. 分解
    • StringをEMailとして
    "[email protected]" match {
    case EMail(user, domain) =>
    (user, domain)
    }
    //=> ("foo", "example.com")
    String as EMail
    Deconstructuring

    View Slide

  23. 分解
    • StringをEMailとして
    "invalid e-mail address" match {
    case EMail(user, domain) =>
    (user, domain)
    }
    //=> MatchError
    String as EMail
    Deconstructuring

    View Slide

  24. 分解
    • StringをEMailとして
    "[email protected]" match {
    case EMail(user, domain) => ...
    }
    #unapply
    String as EMail
    Deconstructuring

    View Slide

  25. 分解
    • StringをEMailとして
    object EMail {
    def unapply(str: String): Option[(String, String)] = {
    val parts = str split "@"
    if (parts.length == 2) Some(parts(0), parts(1))
    else None
    }
    }
    String as EMail
    Deconstructuring

    View Slide

  26. 分解
    val re = """(¥d+)-(¥d+)-(¥d+)""".r
    // 正規表現オブジェクトの生成
    "2012-09-15" match {
    case re(yyyy, mm, dd) =>
    (yyyy, mm, dd)
    }
    // => ("2012", "09", "15")
    // Create a Regex object
    Deconstructuring

    View Slide

  27. 照合
    Array(1, Array(2, 3)) match {
    case Array(a, Array(b, c), d) => null
    case Array(a, List(b, c)) => null
    case Array(0, Array(b, c)) => null
    }
    // => MatchError
    Matching

    View Slide

  28. 代入
    Array(1, Array(2, 3)) match {
    case Array(a, d @ Array(b, c)) =>
    Array(a, b, c, d)
    }
    // => Array(1, 2, 3, Array(2, 3))
    Assignment

    View Slide

  29. Rubyにおける
    パターンマッチ
    Pattern matching in Ruby

    View Slide

  30. pattern-match
    • Scalaのパターンマッチに似た機
    能を実現するためのライブラリ
    – https://github.com/k-tsj/pattern-match
    – gem install pattern-match
    A Scala-like pattern matching library

    View Slide

  31. 基本的な使い方
    require 'pattern-match'
    match([0, [1, 2]]) {
    with(Array.(a, Array.(b, 2)) {
    [a, b] #=> [0, 1]
    }
    with(_[a, _[b, 2]]) { # 上記と同様
    ...
    }
    }
    Same as above
    Basic usage

    View Slide

  32. 基本的な使い方
    proc = match {
    with(_[a, _[b, 2]]) { [a, b] }
    }
    proc.call([0, [1, 2]]) #=> [0, 1]
    引数なし
    No argument
    Basic usage

    View Slide

  33. 分解
    • 分解するために必要なこと
    – Deconstructorのクラスに
    Deconstructableをincludeする
    – Deconstructorに
    deconstructメソッドを定義する
    with(Array.(a, b))
    Deconstructor
    Deconstructuring
    What you need to deconstruct an object
    Include Deconstructable
    in a class of Deconstructor
    Define deconstruct method for Deconstructor

    View Slide

  34. 分解
    class Class
    include PatternMatch::Deconstructable
    end
    def Array.deconstruct(val)
    accept_self_instance_only(val)
    val
    end
    Deconstructuring

    View Slide

  35. 分解
    class Regexp
    include PatternMatch::Deconstructable
    def deconstruct(val)
    m = Regexp.new("¥¥A#{source}¥¥z",
    options).match(val.to_s)
    raise PatternNotMatch unless m
    m.captures.empty? ? [m[0]] : m.captures
    end
    end
    Deconstructuring

    View Slide

  36. 照合/代入
    match([0, [1, 2]]) {
    with(_[a, _[b, c], d]) => nil
    with(_[a, List.(b, c)]) => nil
    with(_[1, _[b, c]]) => nil
    }
    #=> NoMatchingPatternError
    Matching/Assignment

    View Slide

  37. 照合/代入
    • オブジェクトの比較は#===
    match([0, 1]) {
    with(_[Fixnum, 1..10]) { true }
    with(_) { false }
    } #=> true
    Matching/Assignment
    Compare objects by #===

    View Slide

  38. 照合/代入
    • 繰り返し
    match([[0, 1], [2, 3]]) {
    with(_[_[a, b], ___]) {
    [a, b] #=> [[0, 2], [1, 3]]
    }
    }
    Matching/Assignment
    Repetition

    View Slide

  39. 照合/代入
    • 繰り返し
    match([[0, 1], [2, 3]]) {
    with(_[*_[a, b]]) {
    [a, b] #=> [[0, 2], [1, 3]]
    }
    }
    Matching/Assignment
    Repetition

    View Slide

  40. 照合/代入
    • AND(&)/OR(|)/NOT(!)
    match([0, [1]]) {
    with(_[(a & Fixnum), !(_[2] | _[3])]) {
    a #=> 0
    }
    }
    Matching/Assignment

    View Slide

  41. 照合/代入
    • Hash.()
    –Destructuring Assignment(#6414)
    john = {name: "John", last: "Smith"}
    {name: n, last: l} = john
    n // => "John"
    l // => "Smith"
    Matching/Assignment

    View Slide

  42. 照合/代入
    • Hash.()
    –Destructuring Assignment(#6414)
    match({name: "John", last: "Smith"}) {
    with(Hash.(name: n, last: l)) {
    n #=> "John"
    l #=> "Smith"
    }
    }
    Matching/Assignment

    View Slide

  43. 照合/代入
    • Object.()
    –Duck typing style
    match(10) {
    with(Object.(:to_i => i, :to_s.(16) => s)) {
    [i, s] #=> [10, "a"]
    }
    }
    Matching/Assignment

    View Slide

  44. 利用例(テキスト処理)
    birthday,fullname
    2012/4/1,John Smith
    2011/6/3,Jane Smith
    2012/9/15,Pater Smith
    2012/5/22,Mary Smith
    Year: 2012
    Month: 1 - 6
    Month: 4, Name: John, Last: Smith
    Month: 5, Name: Mary, Last: Smith
    Examples(Text processing)
    入力
    Input
    出力
    Output

    View Slide

  45. 利用例(テキスト処理)
    • パターンマッチあり
    ARGF.each(&match {
    with(CSV.(Date.(2012, mm & 1..6, _),
    /(¥w+) (¥w+)/.(name, last))) { ... }
    with(_) { ... }
    })
    Examples(Text processing)
    With pattern matching

    View Slide

  46. 利用例(テキスト処理)
    • パターンマッチなし
    ARGF.each do |i|
    cols = CSV.parse_line(i)
    if cols.length == 2
    date = Date.parse(cols[0]) rescue nil
    m = cols[1].match(/(¥w+) (¥w+)/)
    if date and date.year == 2012 and (1..6).includes?(date.month) and m
    mm = date.month
    name, last = m.captures
    ...
    Examples(Text processing)
    Without pattern matching

    View Slide

  47. 利用例(ノード処理)
    doc = REXML::Document.new(
    'ab'
    )
    match(doc.root) {
    with(Element('ul', attrs, *Element('li', _, Text(txts)))) {
    txts #=> ["a", "b"]
    }
    }
    Examples(Node processing)

    View Slide

  48. デザイン(文法)
    • match式を新設
    • case式を拡張
    • メソッド引数/ブロック引数
    Design(Syntax)
    Add match expression
    Extend case expression
    Method parameters/Block parameters

    View Slide

  49. デザイン(分解)
    • コンテキストに応じた分解
    Time.gm(year, mon = 1, day = 1,
    hour = 0, min = 0, sec = 0, usec = 0)
    Time.(year, mon, day, hour, min, sec, usec)
    Time.(year, mon, day)
    Time.(hour, min, sec, usec)
    Design(Deconstructuring)
    Contextual deconstructuring

    View Slide

  50. デザイン(照合)
    • 正規表現
    match(["a", "b", 0, "c", "d"]) {
    with(_[*i, Fixnum, *j]) {
    [i, j] #=> [["a", "b"], ["c", "d"]]
    }
    }
    Design(Matching)
    Regular expression

    View Slide

  51. デザイン(照合)
    • Mathematicaの例
    Replace[{1, {2, 3}}, (* List *)
    {a_, {b_, c_}} -> (* Pattern *)
    {a, b, c}]
    (* {1, 2, 3} *)
    Design(Matching)
    Examples of Mathematica

    View Slide

  52. デザイン(照合)
    • Mathematicaの例
    Replace[{1, 2, 3, 4, 5},
    {a___, b_, Shortest[c___]} ->
    {a}]
    (* {1, 2, 3, 4} *)
    Design(Matching)
    Examples of Mathematica

    View Slide

  53. デザイン(照合)
    • Mathematicaの例
    Replace[{1, 2, 3, 4, 5},
    {a___, b_, c___}/;b>2 ->
    {a}]
    (* {1, 2} *)
    Design(Matching)
    Examples of Mathematica

    View Slide

  54. デザイン(照合)
    • Setなどに対する照合
    match(Set[1, 2, 3]) {
    with(Set.( ??? )) { ... }
    }
    Design(Matching)
    Matching against data structures like Set

    View Slide

  55. まとめ
    • パターンマッチは非常に強力
    • ぜひ実際にコードを書いてユース
    ケースを共有してください
    Conclusions
    You know the power of pattern
    matching
    We Code.

    View Slide