07
Jul
11

Eigene Extraktoren


Heute nur ein paar Zeilen zu eigenen Extraktoren. Ich denke, einen guten Überblick über die verschiedenen Möglichkeiten gibt Jesse Eichar in seinem Daily Scala Blog. Ich will heute einen ganz einfachen Satz von Extraktoren vorstellen, mit denen man sich in vielen Fällen Guards sparen kann. Angenommen, wir haben folgenden Code:

case class Edge(from:String, to:String)

def makeEdge(p:(String,String)) = p match {
  case (from,to) if from != to => Edge(from, to)
  case _ => error("Can't create edge with identical end points")
}

Wäre es nicht schön, wenn wir einen Extraktor hätten, der auf Ungleichheit prüfen kann? Kein Problem:

object Ne {
   def unapply[T](pair:(T,T)):Option[(T,T)] = 
     if (pair._1 != pair._2) Some(pair) else None
}

def makeEdge(p:(String,String)) = p match {
  case Ne(from,to) => Edge(from, to)
  case _ => error("Can't create edge with identical end points")
}

Nach dem gleichen Schema lässt sich eine ganze Familie von Extraktoren basteln. Für Größenvergleiche benötigen wir zusätzlich einen impliziten Ordering-Parameter, und für den Gleichheits-Extraktor geben wir natürlich nur einen Wert zurück – zwei gleiche wären ja ziemlich witzlos. Hier die ganze Sammlung:

object Eq {
   def unapply[T](pair:(T,T)):Option[T] = 
      if (pair._1 == pair._2) Some(pair._1) else None
}

object Ne {
   def unapply[T](pair:(T,T)):Option[(T,T)] = 
     if (pair._1 != pair._2) Some(pair) else None
}

object Lt {
   def unapply[T](pair:(T,T))(implicit ord: Ordering[T]):Option[(T,T)] = 
     if (ord.lt(pair._1,pair._2)) Some(pair) else None
}

object Le {
   def unapply[T](pair:(T,T))(implicit ord: Ordering[T]):Option[(T,T)] = 
     if (ord.lteq(pair._1,pair._2)) Some(pair) else None
}

object Gt {
   def unapply[T](pair:(T,T))(implicit ord: Ordering[T]):Option[(T,T)] = 
     if (ord.gt(pair._1,pair._2)) Some(pair) else None
}

object Ge {
   def unapply[T](pair:(T,T))(implicit ord: Ordering[T]):Option[(T,T)] = 
     if (ord.gteq(pair._1,pair._2)) Some(pair) else None
}

Für eine Beschränkung habe ich leider noch keine Lösung gefunden, und zwar für Alternativen. Man kann zwar schreiben:

def g(p:(Int,Int)) = p match {
  case (10,20) | (20,10) => println("yes!")
  case _ => println("nope")
}

Aber es ist verboten, in den einzelnen Alternativen Variablen zu belegen, z.B.:

//doesn't work
def g(p:(Int,Int)) = p match {
  case (10,n) | (n,10) => println(n)
  case _ => println("nope")
}

Im Prinzip sollte das für den Compiler kein Problem sein, wenn in beiden Zweigen die gleiche Anzahl Variablen mit den gleichen Typen verwendet wird. Leider scheint es auch mit eigenen Extraktoren nicht möglich zu sein, das gewünschte Verhalten abzubilden. Oder hat jemand vielleicht eine zündende Idee?

So, ich denke das reicht für heute. Demnächst gibt es das Kohl-Ziege-Wolf-Puzzle in Haskell, aber das braucht noch etwas Feinschliff, vor allem der Kohl.

About these ads

0 Responses to “Eigene Extraktoren”



  1. Hinterlasse einen Kommentar

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ photo

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s


Folgen

Erhalte jeden neuen Beitrag in deinen Posteingang.

%d Bloggern gefällt das: