Slide 1

Slide 1 text

Higher Kinded Data Types Jens Grassel . . Wegtam GmbH

Slide 2

Slide 2 text

Motivation

Slide 3

Slide 3 text

Was ist ein Higher Kinded ...? Was ist eigentlich ein ”Higher Kinded Type”? • Ein Typ, der einen anderen enthalten kann. • A[ ] → A[B] • oder leichter verst¨ andlich List[ ] → List[Int] Aber um diese geht es hier nicht direkt.

Slide 4

Slide 4 text

Modelle in so einer Webanwendung Product Owner: ”Wir brauchen eine Registrierung!” • Datenbanktabelle • internes Modell • Registrierungsformular (eigenes Modell) • Validierung • Konvertierung

Slide 5

Slide 5 text

Registrierungsmodelle ( / ) . Datenbanktabelle → geschenkt . internes Modell final case class Customer(id: CustomerID, name: CustomerName, email: EMail, address: PostalAddress, phone: PhoneNumber, contact: ContactName, vat: VATNumber, flag1: BlaBlaFlag, flag2: AnotherBlaBlaFlag) . nicht alle Attribute ”nach außen” durchschleifen . eigenes Modell f¨ ur Registrierung • erlaubt automatische Formulargenerierung • flexibler

Slide 6

Slide 6 text

Registrierungsmodelle ( / ) . Registrierungsmodell final case class RegistrationForm(email: EMail, pass: UserPassword, name: CustomerName, address: PostalAddress, phone: PhoneNumber, contact: ContactName, vat: VATNumber) . vermutlich sowas wie object RegistrationForm { def validate(webForm: Map[String, String]): ValidatedNel[Error, RegistrationForm] = ??? } Validierung ist schonmal nicht schlecht, aber: Parse, don’t validate!

Slide 7

Slide 7 text

Registrierungsmodelle ( / ) Wohin f¨ uhrt uns das? . Registrierungsmodell (wie gehabt) . Registrierungsmodell (Formularendpunkt) final case class RegistrationFormSubmitted(email: Option[EMail], pass: Option[UserPassword], name: Option[CustomerName], ...) . Registrierungsmodell (Parser) final case class RegistrationFormParsed( email: Either[String, EMail], pass: Either[String, UserPassword], name: Either[String, CustomerName], ...) Ihr versteht, was ich meine...

Slide 8

Slide 8 text

Ein anderer Fall... Attribute, die optional sind, aber f¨ ur manche Funktionen gesetzt sein m¨ ussen. • Parameterklasse final case class MyArgs(id: ProgramID, filters: List[Filter], startDate: Option[OffsetDateTime], endDate: Option[OffsetDateTime]) • Funktion A def doSomething(args: MyArgs): ??? = ??? • Funktion B def doSomethingWithDates(args: MyArgs): ??? = { val s = args.startDate.get // crash val e = args.endDate.get // and burn ... }

Slide 9

Slide 9 text

Wie helfen uns HKDs?

Slide 10

Slide 10 text

Sie abstrahieren den Wrapper ums Attribut. • statt verschiedener Modelle, die logisch, aber nicht f¨ ur den Compiler ersichtlich zusammenh¨ angen • ein Modell, das Strukturen der Felder abstrahiert • weniger Boilerplate • De-Duplizierung • strukturierte Beziehungen (f¨ ur Compiler verst¨ andlich)

Slide 11

Slide 11 text

Fall (Registrierung) Annahme: Alle Felder m¨ ussen ausgef¨ ullt und g¨ ultig sein. final case class RegistrationForm[T[_]](email: T[EMail], pass: T[UserPassword], name: T[CustomerName], address: T[PostalAddress], phone: T[PhoneNumber], contact: T[ContactName], vat: T[VATNumber]) in der Anwendung: RegistrationForm[Either[String, _]](...) RegistrationForm[Option](...)

Slide 12

Slide 12 text

Fall (optionale Felder) Das gleiche Prinzip, nur halt nicht f¨ ur alle Felder: final case class MyArgs[T[_]](id: ProgramID, filters: List[Filter], startDate: T[OffsetDateTime], endDate: T[OffsetDateTime])

Slide 13

Slide 13 text

Und was jetzt? - oder - Wie komme ich an die Felder? Machen wir jetzt immer sowas wie foo.bar.get???

Slide 14

Slide 14 text

Identity to the rescue! • aus Cats Bibliothek: type Id[A] = A • soll heißen RegistrationForm[Id](...) MyArgs[Id](...) • f¨ ur Funktionen def doSomethingWithDates(args: MyArgs[Id]): ??? = { val s = args.startDate // safe val e = args.endDate // safe ... }

Slide 15

Slide 15 text

Was fehlt? • komplett automatische Konvertierung (Foo[T] → Foo[Id]) • dieser Teil muß programmiert werden

Slide 16

Slide 16 text

Zusammenfassung • Polymorphismus (auf HKTs) → HKDs erlaubt • Wiederverwendung von Datenstrukturen • Reduzierung von ”duplicate code” • weniger Boilerplate • h¨ ohere Typensicherheit (Compiler hilft)

Slide 17

Slide 17 text

Vielen Dank!