Pattern Matching in Ruby

303dd57f37d64288bb4f0336332a8882?s=47 k_tsj
September 15, 2012

Pattern Matching in Ruby

303dd57f37d64288bb4f0336332a8882?s=128

k_tsj

September 15, 2012
Tweet

Transcript

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

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

    Favorite languages: A CRuby committer
  3. Ruby 2.0 2013/2/24 リリース予定 will be released

  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
  5. 新しい人参が必要 • Multiple VM • JIT • 世代別/並列GC • …

    • パターンマッチ We need a new carrot Generational/Parallel GC Pattern matching
  6. パターンマッチとは What is pattern matching

  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
  8. ?

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

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

    => ... } Pattern matching
  11. 比較 a, (b, c) = [1, [2, 3]] Array(1, Array(2,

    3)) match { case Array(a, Array(b, c)) => ... } Comparing 多重代入 Multiple assignment パターンマッチ Pattern matching
  12. 多重代入の問題点 1. Arrayに限定される Problems of multiple assignment Array only

  13. 多重代入の問題点 a, (b, c), d = [1, [2, 3]] d

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

    of multiple assignment Need it 3. 途中の値が代入できない Can not assign nonterminal value
  15. 多重代入の問題点 1. Arrayに限定される 2. 個数の確認等ができない 3. 途中の式を代入できない 分解機能が弱い 照合機能がない 代入機能が弱い

    Lack of deconstructuring mechanism No matching mechanism Lack of assignment mechanism Problems of multiple assignment
  16. パターンマッチとは (多重代入 + α) + case 分解 + 代入 照合

    Deconstructuring Assignment Matching Multiple assignment What is pattern matching
  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: 関数型プログラミング
  18. Scalaにおける パターンマッチ Pattern matching in Scala

  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
  20. 分解 • ArrayをArrayとして Array(1, Array(2, 3)) match { case Array(a,

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

    List(b, c)) => ... } Deconstructuring List as List
  22. 分解 • StringをEMailとして "foo@example.com" match { case EMail(user, domain) =>

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

    domain) => (user, domain) } //=> MatchError String as EMail Deconstructuring
  24. 分解 • StringをEMailとして "foo@example.com" match { case EMail(user, domain) =>

    ... } #unapply String as EMail Deconstructuring
  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
  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
  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
  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
  29. Rubyにおける パターンマッチ Pattern matching in Ruby

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

    A Scala-like pattern matching library
  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
  32. 基本的な使い方 proc = match { with(_[a, _[b, 2]]) { [a,

    b] } } proc.call([0, [1, 2]]) #=> [0, 1] 引数なし No argument Basic usage
  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
  34. 分解 class Class include PatternMatch::Deconstructable end def Array.deconstruct(val) accept_self_instance_only(val) val

    end Deconstructuring
  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
  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
  37. 照合/代入 • オブジェクトの比較は#=== match([0, 1]) { with(_[Fixnum, 1..10]) { true

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

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

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

    | _[3])]) { a #=> 0 } } Matching/Assignment
  41. 照合/代入 • Hash.() –Destructuring Assignment(#6414) john = {name: "John", last:

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

    with(Hash.(name: n, last: l)) { n #=> "John" l #=> "Smith" } } Matching/Assignment
  43. 照合/代入 • Object.() –Duck typing style match(10) { with(Object.(:to_i =>

    i, :to_s.(16) => s)) { [i, s] #=> [10, "a"] } } Matching/Assignment
  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
  45. 利用例(テキスト処理) • パターンマッチあり ARGF.each(&match { with(CSV.(Date.(2012, mm & 1..6, _),

    /(¥w+) (¥w+)/.(name, last))) { ... } with(_) { ... } }) Examples(Text processing) With pattern matching
  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
  47. 利用例(ノード処理) doc = REXML::Document.new( '<ul><li>a</li><li>b</li></ul>' ) match(doc.root) { with(Element('ul', attrs,

    *Element('li', _, Text(txts)))) { txts #=> ["a", "b"] } } Examples(Node processing)
  48. デザイン(文法) • match式を新設 • case式を拡張 • メソッド引数/ブロック引数 Design(Syntax) Add match

    expression Extend case expression Method parameters/Block parameters
  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
  50. デザイン(照合) • 正規表現 match(["a", "b", 0, "c", "d"]) { with(_[*i,

    Fixnum, *j]) { [i, j] #=> [["a", "b"], ["c", "d"]] } } Design(Matching) Regular expression
  51. デザイン(照合) • Mathematicaの例 Replace[{1, {2, 3}}, (* List *) {a_,

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

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

    c___}/;b>2 -> {a}] (* {1, 2} *) Design(Matching) Examples of Mathematica
  54. デザイン(照合) • Setなどに対する照合 match(Set[1, 2, 3]) { with(Set.( ??? ))

    { ... } } Design(Matching) Matching against data structures like Set
  55. まとめ • パターンマッチは非常に強力 • ぜひ実際にコードを書いてユース ケースを共有してください Conclusions You know the

    power of pattern matching We Code.