Save 37% off PRO during our Black Friday Sale! »

Higher Kinded Data Types

Higher Kinded Data Types

Eine kurze Einführung in Higher Kinded Data Types (Motivation und Beispiele).

16ad3ff954790c142086a2dfde2aea48?s=128

Jens Grassel

March 11, 2021
Tweet

Transcript

  1. Higher Kinded Data Types Jens Grassel . . Wegtam GmbH

  2. Motivation

  3. 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.
  4. Modelle in so einer Webanwendung Product Owner: ”Wir brauchen eine

    Registrierung!” • Datenbanktabelle • internes Modell • Registrierungsformular (eigenes Modell) • Validierung • Konvertierung
  5. 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
  6. 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!
  7. 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...
  8. 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 ... }
  9. Wie helfen uns HKDs?

  10. 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)
  11. 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](...)
  12. 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])
  13. Und was jetzt? - oder - Wie komme ich an

    die Felder? Machen wir jetzt immer sowas wie foo.bar.get???
  14. 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 ... }
  15. Was fehlt? • komplett automatische Konvertierung (Foo[T] → Foo[Id]) •

    dieser Teil muß programmiert werden
  16. Zusammenfassung • Polymorphismus (auf HKTs) → HKDs erlaubt • Wiederverwendung

    von Datenstrukturen • Reduzierung von ”duplicate code” • weniger Boilerplate • h¨ ohere Typensicherheit (Compiler hilft)
  17. Vielen Dank!