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. ύλʔϯϚονࣜ 構文 Expr ::= PostfixExpr 'match' '{' CaseClauses '}' CaseClauses

    ::= CaseClause {CaseClause} CaseClause ::= 'case' Pattern [Guard] '=>' Block Guard ::= 'if' PostfixExpr e match { case p1 => b1 case pn => bn } パターンマッチ式
  2. ύλʔϯϚονࣜ - 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
  3. ύλʔϯϚονͷύλʔϯ • ม਺ύλʔϯ 
 (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
  4. ίϯετϥΫλύλʔϯ ケースクラスと組み合わせて使うパターン case class Person(name: String, mail: String) val person

    = Person("ాத ߽", "[email protected]") val res2 = person match { case Person("ࢁా ଠ࿠", _) => "΍·ͪΌΜ" case Person("ాத ߽", _) => "ͨΜ͝" case _ => "ͳͳ͠" } res2: String = ͨΜ͝
  5. நग़ࢠύλʔϯ 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 が自動的に定義される
  6. λϓϧύλʔϯ 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
  7. val res5 = List("hoge","fuga","piyo") match { case head :: tail

    㱺 tail case _ 㱺 "foobar" } res5: String = hogehoge ListͷύλʔϯϚον
  8. 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ͷύλʔϯϚον
  9. case scala.collection.immutable.::(head, tail) 㱺 … case head :: tail 㱺

    … Scala では次のように解釈されている これは中置演算子パターンでメソッドっぽく見せかけている ListͷύλʔϯϚον
  10. Ԡ༻ྫ 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)
  11. Ԡ༻ྫ // 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 } }
  12. Ԡ༻ྫ 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) | はパターンマッチングのパターンの 「パターン選択子」
  13. ͞ΒʹԠ༻ྫ // 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))}
  14. ͞ΒʹԠ༻ྫ List(tango, sato, john, wang) foreach { person => person

    match { case (R18(_) & Admin(_)) | (Admin(_) & Japanese(_)) => println(person) case _ => () } } Person(tango,34,true,Japan)