Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

?

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

他言語のパターンマッチ 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: 関数型プログラミング

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

分解 • 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

Slide 26

Slide 26 text

分解 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

Slide 27

Slide 27 text

照合 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

Slide 28

Slide 28 text

代入 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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

基本的な使い方 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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

分解 • 分解するために必要なこと – 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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

分解 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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

利用例(テキスト処理) 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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

利用例(テキスト処理) • パターンマッチなし 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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

デザイン(分解) • コンテキストに応じた分解 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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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