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

たぶん便利なパターンマッチ

Go Tanaka
September 08, 2016

 たぶん便利なパターンマッチ

Scalaの便利なパターンマッチの紹介。
特殊なパターンマッチの仕組みと応用。

Go Tanaka

September 08, 2016
Tweet

More Decks by Go Tanaka

Other Decks in Programming

Transcript

  1. ͨͿΜศརͳύλʔϯϚον
    @tan_go238

    View full-size slide

  2. ΞδΣϯμ
    - ύλʔϯϚονࣜ
    - ύλʔϯϚονͷύλʔϯ
    - List ͷύλʔϯϚον
    - Ԡ༻ྫ

    View full-size slide

  3. ύλʔϯϚονࣜ
    構文
    Expr ::= PostfixExpr 'match' '{' CaseClauses '}'
    CaseClauses ::= CaseClause {CaseClause}
    CaseClause ::= 'case' Pattern [Guard] '=>' Block
    Guard ::= 'if' PostfixExpr
    e match {
    case p1 => b1
    case pn => bn
    }
    パターンマッチ式

    View full-size slide

  4. ύλʔϯϚονࣜ - if Ͱ৚݅ࢦఆ
    val res1 = "piyopiyo" match {
    case p if p.length < 5 => "short piyo"
    case p if p.length >= 5 => "long piyo"
    }
    res1: String = long piyo

    View full-size slide

  5. ύλʔϯϚονͷύλʔϯ
    • ม਺ύλʔϯ 

    (Variable Patterns)
    • ܕ෇͖ύλʔϯ 

    (Typed Patterns)
    • ύλʔϯόΠϯμʔ 

    (Pattern Binders)
    • Ϧςϥϧύλʔϯ 

    (Literal Patterns)
    • ҆ఆԋࢉࢠύλʔϯ 

    (Stable Identifier Patterns)
    • ίϯετϥΫλύλʔϯ 

    (Constructor Patterns)
    • λϓϧύλʔϯ 

    (Tuple Patterns)
    • நग़ࢠύλʔϯ 

    (Extractor Patterns)
    • γʔέϯεύλʔϯ 

    (Pattern sequences)
    • தஔԋࢉࢠύλʔϯ 

    (Infix Operation Patterns)
    • ύλʔϯબ୒ࢠ 

    (Pattern Alternatives)
    • XML Patterns

    View full-size slide

  6. ίϯετϥΫλύλʔϯ
    ケースクラスと組み合わせて使うパターン
    case class Person(name: String, mail: String)
    val person = Person("ాத ߽", "[email protected]")
    val res2 = person match {
    case Person("ࢁా ଠ࿠", _) => "΍·ͪΌΜ"
    case Person("ాத ߽", _) => "ͨΜ͝"
    case _ => "ͳͳ͠"
    }
    res2: String = ͨΜ͝

    View full-size slide

  7. நग़ࢠύλʔϯ
    class Piyo(val piyo: String, val hoge: String)
    object PiyoPiyo {
    def unapply(p: Piyo) = Some(p.piyo)
    }
    val foo = new Piyo("piyopiyo", "hogehoge")
    val res3 = foo match {
    case PiyoPiyo(p) => p
    case _ => "not piyo..."
    }
    res3: String = piyopiyo
    unapplyが定義されていれば、パターンマッチができる (extractor:抽出子)
    ※ case class は unapply が自動的に定義される

    View full-size slide

  8. λϓϧύλʔϯ
    val res4 = ("piyo", "hoge") match {
    case ("piyo", "fuga") => "piyo, fuga"
    case ("piyo", _) => "piyo, something"
    case (_, "hoge") => "something, hoge"
    case (_, _) => "something, something"
    }
    res4: String = piyo, something

    View full-size slide

  9. val res5 = List("hoge","fuga","piyo") match {
    case head :: tail 㱺 tail
    case _ 㱺 "foobar"
    }
    res5: String = hogehoge
    ListͷύλʔϯϚον

    View full-size slide

  10. val res5 = List("hoge","fuga","piyo") match {
    case head :: tail 㱺 "hogehoge"
    case _ 㱺 "foobar"
    }
    res5: String = hogehoge
    一見 List のメソッドのように見える・・・
    http://www.scala-lang.org/api/2.11.8/#scala.collection.immutable.$colon$colon
    でも実体は :: という case class
    ListͷύλʔϯϚον

    View full-size slide

  11. case scala.collection.immutable.::(head, tail) 㱺 …
    case head :: tail 㱺 …
    Scala では次のように解釈されている
    これは中置演算子パターンでメソッドっぽく見せかけている
    ListͷύλʔϯϚον

    View full-size slide

  12. :: クラスは case class なのでコンストラクタパターンでパターンマッチしている
    unapply を書けば抽出子パターンで同等のことが実現可能
    参考:
    http://www.scala-lang.org/api/2.11.8/#scala.collection.$plus$colon$
    ListͷύλʔϯϚον
    val res5 = List("hoge","fuga","piyo") match {
    case scala.collection.immutable.::(head, tail) 㱺 "hogehoge"
    case _ 㱺 "foobar"
    }
    res5: String = hogehoge

    View full-size slide

  13. Ԡ༻ྫ
    sealed class Nationality
    case object Japan extends Nationality
    case object US extends Nationality
    case object China extends Nationality
    case class Person(
    name: String, age: Int, admin: Boolean, nationality: Nationality
    )
    val tango = Person("tango", 34, true, Japan)
    val sato = Person("sato", 23, false, Japan)
    val john = Person("john", 16, true, US)
    val wang = Person("wang", 19, false, China)

    View full-size slide

  14. Ԡ༻ྫ
    // Admin ͩͬͨΒϚον
    object Admin {
    def unapply(p: Person) = p match {
    case Person(_, _, true, _) 㱺 Some(p)
    case _ 㱺 None
    }
    }
    // ೔ຊਓʹϚον
    object Japanese {
    def unapply(p: Person) = p match {
    case Person(_, _, _, Japan) 㱺 Some(p)
    case _ 㱺 None
    }
    }

    View full-size slide

  15. Ԡ༻ྫ
    List(tango, sato, john, wang) foreach { person 㱺
    person match {
    case Admin(_) | Japanese(_) 㱺 println(person)
    case _ 㱺 ()
    }
    }
    Person(tango,34,true,Japan)
    Person(sato,23,false,Japan)
    Person(john,16,true,US)
    | はパターンマッチングのパターンの 「パターン選択子」

    View full-size slide

  16. ͞ΒʹԠ༻ྫ
    // 18ࡀҎ্ʹϚον
    object R18 {
    def unapply(p: Person) = p match {
    case Person(_, age, _, _) if age >= 18 => Some(p)
    case _ => None
    }
    }
    object & { def unapply[A](a: A) = Some((a, a))}

    View full-size slide

  17. ͞ΒʹԠ༻ྫ
    List(tango, sato, john, wang) foreach { person =>
    person match {
    case (R18(_) & Admin(_)) | (Admin(_) & Japanese(_)) => println(person)
    case _ => ()
    }
    }
    Person(tango,34,true,Japan)

    View full-size slide

  18. ·ͱΊ
    • ScalaͷύλʔϯϚον͸ͱͯ΋ศར
    • ΩϞ͍
    • flatMap (ͱforࣜ) ͱύλʔϯϚον͕Θ͔Ε
    ͹࠷ॳͷScalaͷ೉͕ؔ୤ग़Ͱ͖Δײ͢͡Δ
    ʢ˞ݸਓͷײ૝Ͱ͢ʣ

    View full-size slide

  19. ࢀߟ
    • http://tototoshi.hatenablog.com/entry/
    20120116/1326640306
    • http://www.scala-lang.org/docu/files/
    LangSpec2.8-ja_JP.pdf
    • http://seratch.hatenablog.jp/entry/
    20110429/1304090707

    View full-size slide