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

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

Avatar for Go Tanaka Go Tanaka
September 08, 2016

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

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

Avatar for Go Tanaka

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)