Skip to content

Instantly share code, notes, and snippets.

@ymnk
Created October 21, 2010 06:35
Show Gist options
  • Save ymnk/638058 to your computer and use it in GitHub Desktop.
Save ymnk/638058 to your computer and use it in GitHub Desktop.
Sample programs for "Querying a Dataset with Scala's Pattern Matching", which
is available at
http://notes.langdale.com.au/Querying_a_Dataset_with_Scala_s_Pattern_Matching.html
$ scalac *.scala
$ scala
Welcome to Scala version 2.8.0.final (Java HotSpot(TM) Client VM, Java 1.6.0_16).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import TheFamily._
import TheFamily._
scala> ADatasetAndAQuery.check("Hisahito")
res0: String = Hisahito's parents are: Set(Kiko, Fumihito)
scala>
import TheFamily.{Name, parents, children}
object ADatasetAndAQuery {
class Extractor[A,B]( f: A => Option[B] ) {
def unapply( a: A ) = f(a)
}
val Parents = new Extractor(parents.get)
val Children = new Extractor(children.get)
val check: Name => String = {
case s@Parents(p) => "%s's parents are: %s".format(s, p)
case s@Children(c) => "%s's parents are unknown but has children: %s".format(s, c)
case s => "Don't know any of %s's relatives".format(s)
}
/*
def check(s: Name) = s match {
case Parents(p) => "%s's parents are: %s".format(s, p)
case Children(c) => "%s's parents are unknown but has children: %s".format(s, c)
case _ => "Don't know any of %s's relatives".format(s)
}
*/
}
import TheFamily.Name
import CreatingALanguage.{Brothers, Sisters, Siblings}
object ConjunctionsAndDisjunctions {
object & { def unapply[A](a: A) = Some(a, a) }
val check3: Name => String = {
case s@(Brothers(_) & Sisters(_)) =>
"%s has both brother(s) and sister(s)".format(s)
case s@Siblings(x) =>
"%s's siblings are all the same sex %s".format(s, x)
case s => "%s has no siblings".format(s)
}
}
import TheFamily.{Name, parents, children, male, female}
import TraversalsAndFilters.{Extractor, Flattener}
object CreatingALanguage {
def pattern[B](pf: PartialFunction[Name,B]) =
new Extractor(pf.lift)
val Parents = new Extractor(parents.get)
val Children = new Extractor(children.get)
val Female = pattern { case n if female contains n => n }
val GrandChildren =
pattern { case Children(Children(c)) => c }
val GrandDaughters =
pattern { case GrandChildren(Female(c)) => c }
val Mother = pattern { case Parents(Female(p)) => p }
val Siblings = pattern {
case self @ Parents(Children(siblings)) if(siblings.size != 1) =>
siblings - self
}
val Sisters = pattern { case Siblings(Female(s)) => s }
val Male = pattern { case n if male contains n => n }
val Brothers = pattern { case Siblings(Male(b)) => b }
}
object TheFamily {
type Name = String
val male: Set[Name] =
Set("Hirohito",
"Akihito", "Masahito",
"Naruhito", "Fumihito",
"Hisahito")
val female: Set[Name] =
Set("Nagako",
"Michiko", "Shigeko", "Sachiko", "Atsuko", "Takako",
"Sayako", "Masako", "Kiko",
"Aiko", "Mako", "Kako")
val children: Map[Name, Set[Name]] =
Map("Hirohito" -> Set("Shigeko", "Sachiko", "Atsuko",
"Akihito", "Masahito", "Takako"),
"Nagako" -> Set("Shigeko", "Sachiko", "Atsuko",
"Akihito", "Masahito", "Takako"),
"Akihito" -> Set("Naruhito", "Fumihito", "Sayako"),
"Michiko" -> Set("Naruhito", "Fumihito", "Sayako"),
"Naruhito" -> Set("Aiko"),
"Masako" -> Set("Aiko"),
"Fumihito" -> Set("Mako", "Kako", "Hisahito"),
"Kiko" -> Set("Mako", "Kako", "Hisahito"))
private val empty = Map.empty[Name, Set[Name]]
private def invert(s: Map[Name, Set[Name]]) = s.foldLeft(empty){
case (m, (key, set)) =>
set.foldLeft(m){ (m, s) =>
m + (s -> (m.get(s).getOrElse(Set.empty[Name])+key))
}
}
val parents: Map[Name, Set[Name]] = invert(children)
}
import TheFamily.{Name, parents, children, male, female}
object TraversalsAndFilters {
class Extractor[A,B](f: A => Option[B]) {
def unapply( a: A) = f(a)
def unapply[C](ta: Traversable[A])
(implicit g: Flattener[B,C]): Option[C] =
g(ta.view.map(f))
}
trait Flattener[B,C] extends
(Traversable[Option[B]] => Option[C])
class DefaultFlattener {
implicit def defaultFlattener[B] =
new Flattener[B,Traversable[B]] {
def apply(tb: Traversable[Option[B]]): Option[Traversable[B]] =
nonEmpty(tb.flatten)
}
}
object Flattener extends DefaultFlattener {
implicit def flattenSets[E] = new Flattener[Set[E],Set[E]] {
def apply( tb: Traversable[Option[Set[E]]]): Option[Set[E]] =
nonEmpty(tb.flatten.flatten.toSet)
}
}
private def nonEmpty[T <: Traversable[_]]( t: T ) =
if( t isEmpty ) None else Some(t)
val Parents = new Extractor(parents.get)
val Children = new Extractor(children.get)
def check2: Name => String = {
case s@Children(Children(c)) =>
"%s's grandchildren are: %s".format(s, c)
case s@Children(_) =>
"%s has children but no grandchildren".format(s)
case s =>
"%s is childless".format(s)
}
val Female = new Extractor((s:Name) => female.find(s == ))
def check3: Name => String = {
case s@Children(Children(Female(d))) =>
"%s's granddaughters are: %s".format(s, d )
case s@Children(Children(_)) =>
"%s has grandchildren but no granddaughters".format(s)
case s =>
"%s has no grandchildren".format(s)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment