13.07.2015 Aufrufe

Monaden & Co. Funktionale Konzepte in Scala - Lars Hupel

Monaden & Co. Funktionale Konzepte in Scala - Lars Hupel

Monaden & Co. Funktionale Konzepte in Scala - Lars Hupel

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

Typklassen – Verwendungngenerische Funktionen können Typen e<strong>in</strong>schränkensum :: Numeric a => [a] -> asum [] = zerosum (x : xs) = add x (sum xs)nEntsprechung: der Funktion wird e<strong>in</strong>e Menge vonOperationen "implizit" bereitgestellt> sum [(1.0, 2.0), (3.0, 4.0)](4.0,6.0)<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 7


Typklassen <strong>in</strong> <strong>Scala</strong> – ImplementationnImplementation als Wert oder Funktionval floatNumeric = new Numeric[Float] {def add(a1: Float, a2: Float) = a1 + a2def neg(a: Float) = -aval zero: Float = 0.0f}def tupleNumeric[A, B](na: Numeric[A], nb: Numeric[B]) =new Numeric[(A, B)] {def add(a1: (A, B), a2: (A, B)) = …}<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 9


Typklassen <strong>in</strong> <strong>Scala</strong> – VerwendungnFunktionen erhalten zusätzlichen Parameterdef sum[A](list: List[A], num: Numeric[A]): A =if (list.isEmpty)num.zeroelsenum.add(list.head, sum(list.tail, num))<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 10


Typklassen <strong>in</strong> <strong>Scala</strong> – VerwendungnNachteil: explizite Angabe der Implementation> sum(List((1.0f, 2.0f), (3.0f, 4.0f)),tupleNumeric(floatNumeric, floatNumeric))res0: (Float, Float) = (4.0,6.0)<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 11


Typklassen <strong>in</strong> <strong>Scala</strong> – implizite ParameternnnLösung: Schlüsselwort implicitzwei implizite Mechanismen <strong>in</strong> <strong>Scala</strong>:nnKonvertierung e<strong>in</strong>es Objekts, wenn auf diesem e<strong>in</strong>e nichtvorhandene Methode aufgerufen wirdE<strong>in</strong>setzen e<strong>in</strong>es Werts passenden Typs als Methodenparameterimplicit muss sowohl vor dem Parameter als auch vor derImplementation notiert werden<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 12


Typklassen <strong>in</strong> <strong>Scala</strong> – implizite Parameterdef sum[A](list: List[A])(implicit num: Numeric[A]): A =if (list.isEmpty)num.zeroelsenum.add(list.head, sum(list.tail))> sum(List((1.0f, 2.0f), (3.0f, 4.0f)))res0: (Float, Float) = (4.0,6.0)■<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 13


K<strong>in</strong>ds – MotivationnnnBeispiel: man verwendet mehrere Bibliotheken, die allesamteigene (generische) <strong>Co</strong>nta<strong>in</strong>er-Typen verwendenmanuelles Konvertieren ist fehleranfällig→ Typklassen, um geme<strong>in</strong>same Operationen anzubietentrait ListLike[T] {def toSet(list: T): Set[?]}nProblem: Generizität → was setzt man als Typparameter e<strong>in</strong>?<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 14


K<strong>in</strong>ds – MotivationnnTypen klassifizieren WerteWas klassifiziert Typen?<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 15


K<strong>in</strong>ds – TypkonstruktorennnnnDatenkonstruktoren erzeugen DatenTypkonstruktoren erzeugen Typenauch bekannt als "parametrische Polymorphie"… oder <strong>in</strong> Java: "Generics"<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 16


K<strong>in</strong>ds – Typkonstruktorennn"K<strong>in</strong>d" bezeichnet die Struktur e<strong>in</strong>es TypkonstruktorsNotationnn* steht für beliebigen Typ-> steht für Abbildung (<strong>in</strong> <strong>Scala</strong>: generische Klasse)<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 17


K<strong>in</strong>ds – BeispieleDatenstruktur Deklaration K<strong>in</strong>dListe class List[A] * -> *Paar class Tuple2[A, B] (* x *) -> *Applikation type Ap[T[_], S] = T[S] ((* -> *) x *) -> *<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 18


K<strong>in</strong>ds – Lösungnnnursprüngliches Problem: ListenLösung <strong>in</strong> Haskell: wird von Typ<strong>in</strong>ferenz erledigtLösung <strong>in</strong> <strong>Scala</strong>: K<strong>in</strong>d explizit angebentrait ListLike[T[_]] {def toSet[E](list: T[E]): Set[E]}implicit val list = new ListLike[List] {def toSet[E](list: List[E]) = list.toSet}<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 19


Typklassen und K<strong>in</strong>ds"Someone <strong>in</strong> the #haskell IRC channel used (***),and when I asked lambdabot to tell me its type, it pr<strong>in</strong>tedout scary gobbledygook that didn’t even fit on one l<strong>in</strong>e!Then someone used fmap fmap fmap and my bra<strong>in</strong>exploded." – aus "The Typeclassopedia" von Brent Yorgey> :type (***)(Arrow a) =>a b c -> a b' c' -> a (b, b') (c, c')<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 20


Haskells Typklassenhierarchieaus "The Typeclassopedia"<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 21


<strong>Scala</strong>z"The <strong>in</strong>tention of <strong>Scala</strong>z is to <strong>in</strong>clude general functionsthat are not currently available <strong>in</strong> the core <strong>Scala</strong> API."– Projektbeschreibung auf http://code.google.com/p/scalaz/nnnbesteht aus mehreren (unabhängigen) Teilenfür diesen Vortrag von Interesse: TypklassenNachbildung der Hierarchie aus Haskells Bibliothek<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 22


<strong>Scala</strong>z – FunctorsnnnIntuition: "<strong>Co</strong>nta<strong>in</strong>er, der Elemente enthält"OperationennAbbildung der Elemente vom Typ A auf Typ BBed<strong>in</strong>gungennnIdentitäta == fmap(identity, a)Kompositionfmap(f compose g, a) == fmap(f, fmap(g, a))<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 23


<strong>Scala</strong>z – Functorstrait Functor[F[_]] {def fmap[A, B](f: A => B, r: F[A]): F[B]}implicit val optionFunctor =new Functor[Option] {def fmap[A, B](f: A => B, r: Option[A]) =r map f}<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 24


<strong>Scala</strong>z – Functorsnn<strong>Scala</strong>z def<strong>in</strong>iert e<strong>in</strong>e Reihe von Functors auch für Klassenaus der Java-Bibliothek wie z. B. CallableVorteil liegt auf der Hand: verschiedene Datenstrukturenlassen sich gleich behandeln"Polymorphism captures similar structure over differentvalues, while type classes capture similar operations overdifferent structures."– aus "The Haskell School of Expression" von Paul Hudak<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 25


<strong>Scala</strong>z – PurennIntuition: "verpackt Wert <strong>in</strong> <strong>Co</strong>nta<strong>in</strong>er"OperationennKonvertieren e<strong>in</strong>es Werts vom Typ A <strong>in</strong> e<strong>in</strong>en <strong>Co</strong>nta<strong>in</strong>er desTyps P[A]trait Pure[P[_]] {def pure[A](a: => A): P[A]}<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 26


<strong>Scala</strong>z – PurenAnwendungsbeispiel: aufwändige Berechnungen <strong>in</strong> e<strong>in</strong>Future verlegenimplicit val futurePure =new Pure[Future] {def pure[A](a: => A) = new FutureTask(new Callable[A] {def call = a})}<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 27


<strong>Scala</strong>z – ApplicativennnIntuition: "Berechnungskontext"Operationen (zusätzlich zu Pure und Functor)nAnwenden e<strong>in</strong>er Funktion, die selbst <strong>in</strong> den <strong>Co</strong>nta<strong>in</strong>er verpacktist, auf e<strong>in</strong>en Wertdie meisten Functors s<strong>in</strong>d auch Applicatives<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 28


<strong>Scala</strong>z – Applicativetrait Applicative[Z[_]]extends Pure[Z] with Functor[Z] {}def apply[A, B](f: Z[A => B], a: Z[A]): Z[B]nalternative Schreibweise der Signatur von apply ("Kontext")Z[A => B] => (Z[A] => Z[B])<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 29


<strong>Scala</strong>z – ApplicativennAnwendungsbeispiel: Listen "mal anders"Idee: Listen repräsentieren Ergebnisse <strong>in</strong> e<strong>in</strong>ernichtdeterm<strong>in</strong>istischen Berechnungval nondet = new Applicative[List] {def pure[A](a: => A) = List(a)def apply[A, B](fs: List[A => B], as: List[A]) =for (f


<strong>Scala</strong>z – Applicativenondet.apply(nondet.fmap(f, List(3,5)), List(2,6))<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 31


<strong>Scala</strong>z – MonadsnnIntuition: "komb<strong>in</strong>iert Berechnungen"Operationen (zusätzlich zu Applicative)n"flatMap"trait Monad[M[_]] extends Applicative[M] {def b<strong>in</strong>d[A, B](a: M[A], f: A => M[B]): M[B]}<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 32


<strong>Scala</strong>z – MonadsnnAnwendungsbeispiel: Logg<strong>in</strong>gProblem: Wert wird <strong>in</strong> mehreren Schritten errechnet,Teilergebnisse sollen protokolliert werdenn Lösung: Modellierung als (List[Str<strong>in</strong>g], A)nnA – aktuelles TeilergebnisList[Str<strong>in</strong>g] – akkumuliertes Protokoll<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 33


<strong>Scala</strong>z – Monadstype <strong>Co</strong>mputation[A] = (List[Str<strong>in</strong>g], A)val logger = new Monad[<strong>Co</strong>mputation] {}def pure[A](a: => A) = (Nil, a)def b<strong>in</strong>d[A, B](a: <strong>Co</strong>mputation[A], f: A => <strong>Co</strong>mputation[B])= {val (log, value) = aval res = f(value)(log ::: res._1, res._2)}<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 34


<strong>Scala</strong>z – Monads> logger.pure("foo")res0: (List[Str<strong>in</strong>g], Str<strong>in</strong>g) = (List(),foo)> logger.b<strong>in</strong>d(res0,(x: Str<strong>in</strong>g) => (List("add<strong>in</strong>g to " + x),x + "bar"))res1: (List[Str<strong>in</strong>g], Str<strong>in</strong>g) =(List(add<strong>in</strong>g to foo),foobar)■<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 35


Path-dependent typesnnn<strong>Scala</strong> behandelt <strong>in</strong>nere Klassen anders als JavaGeme<strong>in</strong>samkeit: statische <strong>in</strong>nere Klassen haben ke<strong>in</strong>eReferenz auf die äußere Klassebei nicht-statischen <strong>in</strong>neren Klassen: <strong>in</strong> <strong>Scala</strong> ist die Referenzauf die äußere Klasse Bestandteil des Typs<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 36


Path-dependent typesclass Outer {class Inner {}}> new Outerres0: Outer = Outer@19c46bab> new res0.Innerres1: res0.Inner = Outer$Inner@36618533> new Outerres2: Outer = Outer@8afcd0c> new res2.Innerres3: res2.Inner = Outer$Inner@90affe<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 37


Path-dependent types – Konsequenzennnnnn<strong>in</strong>nere Exemplare zweier verschiedener äußerer Referenzennicht mite<strong>in</strong>ander kompatibelbirgt Probleme bei der Java-InteroperabilitätLösung: ProjektionenOuter#Inner steht für alle Exemplare von Inner<strong>in</strong> <strong>Scala</strong> jedoch: reichhaltige neue Möglichkeiten<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 38


Path-dependent types – AnwendungnAnwendungsbeispiel: Bereichsdatentypnnne<strong>in</strong>e Objekt ist mit e<strong>in</strong>em Zahlenbereich assoziiertMethoden dieses Objekts sollen nun nur auf Zahlen aus diesemBereich operierenZahlen außerhalb des Bereichs sollen zu <strong>Co</strong>mpiler-Fehler führen<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 39


Path-dependent types – Zahlbereicheclass Range(beg<strong>in</strong>: Int, end: Int) {class RangeInt private[Range](val n: Int) {def next: Option[Range.this.RangeInt] =if (n < end) Some(new RangeInt(n+1))elseNone}}def first = new RangeInt(beg<strong>in</strong>)def last = new RangeInt(end)class HasRange {val myRange: Range = new Range(1, 10)def func(i: myRange.RangeInt) = pr<strong>in</strong>tln(i.n)}<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 40


Path-dependent types – Zahlbereiche> new HasRangeres0: HasRange = HasRange@5b927504> res0.func(res0.myRange.first)1> new Range(11, 20)res1: Range = Range@790f2f3c> res0.func(res1.first)error: type mismatch;found : res1.RangeIntrequired: res0.myRange.RangeInt■<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 41


Heterogeneous ListsnnnnnnProblem: Funktionen mit mehreren RückgabewertenStandardlösung: Verwendung von Tupeln<strong>in</strong> <strong>Scala</strong>: jede Stelligkeit eigene Klasse→ begrenzte StelligkeitLösung: "Heterogeneous Lists"(statisch typisierte) Listen mit une<strong>in</strong>heitlichen Elementtypen<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 42


Heterogeneous Lists – Implementationsealed trait HListf<strong>in</strong>al case class H<strong>Co</strong>ns[H, T


Heterogeneous Lists – VerwendungnErzeugung von HLists> def getValues = 3 :: "foo" :: HNilgetValues: H<strong>Co</strong>ns[Int,H<strong>Co</strong>ns[Str<strong>in</strong>g,HNil.type]]> getValuesres0: H<strong>Co</strong>ns[…] = H<strong>Co</strong>ns(3,H<strong>Co</strong>ns(foo,HNil))<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 44


Heterogeneous Lists – VerwendungnZugriff auf Elemente: Pattern Match<strong>in</strong>g> getValues match { case H<strong>Co</strong>ns(x, _) => x }res0: Int = 3> getValues match {case H<strong>Co</strong>ns(_, H<strong>Co</strong>ns(y, _)) => y}res1: Str<strong>in</strong>g = foo<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 45


Heterogeneous Lists – VerwendungnZugriff auf Elemente: Indexbasiertnnne<strong>in</strong>e Funktion HList[H, T] => Int => Any möglich, abernicht hilfreichIdee: <strong>in</strong>dex-Funktion muss e<strong>in</strong>en Typparameter haben, der diePosition <strong>in</strong> der Liste repräsentiert→ Peano-Numerale<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 46


Peano-Numeralenals Wertetrait Natcase object Zerocase class Succ(n: Nat)val two = Succ(Succ(Zero))nals Typentrait Nattrait Zero extends Nattrait Succ[N


Peano-Numerale und HListtrait AccessN[L


Peano-Numerale und HList<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 49


Peano-Numerale und HListcase class H<strong>Co</strong>ns[H, T


Peano-Numerale und HList – Beispiel> val list = 3 :: "foo" :: 5.3 :: HNil> list(_0)res0: Int = 3> list(_1)res1: Str<strong>in</strong>g = foo> list(_2)res2: Double = 5.3> list(_3)error: could not f<strong>in</strong>d implicit value forparameter access: AccessN[H<strong>Co</strong>ns[Int,H<strong>Co</strong>ns[Str<strong>in</strong>g, …]], R]<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 51


Heterogeneous Lists – VorteilennnnnnVerwalten von verschiedenen Typen, ohne e<strong>in</strong>e Klasseanlegen zu müssenTupel beliebiger Stelligkeitke<strong>in</strong> Verlust von Typ<strong>in</strong>formationen verglichen mit List[Any]→ <strong>Co</strong>mpiler kann falsche Verwendung erkennendank <strong>Scala</strong>s Syntaxzucker "fühlen" sich HLists wie normaleListen annebenbei: s<strong>in</strong>d auch <strong>in</strong> Java möglich, aber viel Overheadnötig<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 52


Heterogeneous Lists – AnwendungnnnnAnwendungsbeispiel: typsicheres pr<strong>in</strong>tfProblem: Signatur von Str<strong>in</strong>g.format stellt nicht sicher,dass die Argumente zum Formatstr<strong>in</strong>g passen→ <strong>Co</strong>mpiler kann Fehler nicht aufspürenIdee: Funktion konstruieren, die e<strong>in</strong>e HList von denArgumenten nimmt und diese formatiert<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 53


Typsichere Formatierungtype Formattable[T] = T => Str<strong>in</strong>gtrait Formatter[Params Str<strong>in</strong>g) { self =>def :~:[T](f: Formattable[T]):Formatter[H<strong>Co</strong>ns[T, Params]] =new Formatter[H<strong>Co</strong>ns[T, Params]] {def apply(params: H<strong>Co</strong>ns[T, Params]):Str<strong>in</strong>g =f(params.head) + self(params.tail)}}<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 54


Typsichere FormatierungnBeispiel: konstanter Str<strong>in</strong>gdef const(s: Str<strong>in</strong>g): Formattable[Unit] =new Formattable[Unit] {def apply(u: Unit) = s}nBeispiel: Abschneiden von Zeichen (substr<strong>in</strong>g)def subs(start: Int): Formattable[Str<strong>in</strong>g] =new Formattable[Str<strong>in</strong>g] {def apply(s: Str<strong>in</strong>g) = s.substr<strong>in</strong>g(start)}<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 55


Typsichere Formatierung> const("foo") :~: subs(3) :~: const("bar")res0: HLists.Formatter[HLists.H<strong>Co</strong>ns[Unit,HLists.H<strong>Co</strong>ns[Str<strong>in</strong>g,HLists.H<strong>Co</strong>ns[Unit,HLists.HNil.type]]]] = > res0(() :: "abab" :: () :: HNil)res1: Str<strong>in</strong>g = foobbar> res0(() :: 3 :: () :: HNil)error: type mismatch; …<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 56


Typsichere FormatierungnnVorteilennn<strong>Co</strong>mpiler kann Formatierung prüfen→ weniger Exceptionsselbst def<strong>in</strong>ierte Operatoren erhöhen (richtig e<strong>in</strong>gesetzt) dieLesbarkeitNachteilennngezeigte Lösung vere<strong>in</strong>facht, benötigt noch Tricks zum LaufenFehlermeldungen können sehr unübersichtlich werden"Denken <strong>in</strong> Typen" erfordert <strong>in</strong> der Regel e<strong>in</strong>ige E<strong>in</strong>gewöhnung<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 57■


Fragen?Vielen Dank!hupel@<strong>in</strong>.tum.de<strong>Monaden</strong> & <strong>Co</strong>. – <strong>Lars</strong> <strong>Hupel</strong> <strong>Co</strong>pyright © 2011 MATHEMA Software GmbH 58

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!