Kann mir jemand erklären, wozu die Shapeless-Bibliothek dient? [geschlossen]

70

Kann mir jemand in einfachen Worten erklären, wofür die Shapeless-Bibliothek gedacht ist?

Scala verfügt über Generika und Vererbungsfunktionen, daher bin ich etwas verwirrt, wofür Shapeless gedacht ist.

Vielleicht wäre ein Anwendungsfall zur Klärung hilfreich.

loyalflow
quelle

Antworten:

50

Es ist etwas schwer zu erklären, da formlos eine Vielzahl von Funktionen bietet. Ich würde es wahrscheinlich einfacher finden, "in einfachen Worten zu erklären, wofür Variablen sind". Sie möchten auf jeden Fall mit der Funktionsübersicht beginnen .

Im Großen und Ganzen geht es bei Shapeless um das Programmieren mit Typen. Arbeiten zur Kompilierungszeit, die üblicherweise zur Laufzeit ausgeführt werden, genaue Verfolgung des Typs jedes Elements in einer Liste, Übersetzen von Tupeln über HListen in Fallklassen, Erstellen polymorpher Funktionen (im Gegensatz zu Methoden), usw.

Ein typisches Nutzungsszenario würde ungefähr so ​​aussehen:

  • Lesen Sie eine Reihe von Werten von irgendwo in ein List
  • Führen Sie eine typsichere Besetzung davon Listin eineHList
  • Abbildung darüber HListmit einer polymorphen Funktion, die z. B. Werte normalisiert
  • konvertiere das 3. Element (das statisch als ein bekannt ist Int ) in eine 0-aufgefüllte Zeichenfolge
  • Erstellen Sie eine Fallklasse mit Werten aus der HList

Als Referenz wird ein HListwird eine genaue Art, wie Int :: String :: Boolean :: HNil(ja, das wirklich ist ein einziger Typ) , wo alles festgenagelt und die Größe festgelegt ist. Sie müssen also entweder zur Kompilierungszeit genau wissen, was in Ihre HList aufgenommen wird, oder Sie benötigen die typsichere Besetzung.

Wenn Sie eine tailsolche HList verwenden, erhalten Sie eine String :: Boolean :: HNilGarantie und eine Garantiezeit für die Kompilierung, dass der Leiter dieser Liste eine sein wird String. Wenn Sie dem Kopf einen Wert voranstellen, bleiben in ähnlicher Weise alle beteiligten Typen erhalten.

Shapeless wird auch mit der GenericTypklasse geliefert, sodass Sie HList-Operationen auch für Tupel und Fallklassen verwenden können.

Die anderen Funktionen, die ich normalerweise benutze, sind:

  • Coproducts, Mit denen Sie statisch „ein Wert als zB geben String, Doubleoder Int, aber sonst nichts“ (ähnlich wie Either, aber nicht beschränkt auf nur zwei Möglichkeiten)

  • Lenses, die das Arbeiten mit verschachtelten Fallklassen vereinfachen.

Kevin Wright
quelle
32

Das Betrachten eines HListist etwas, das verwirrend erscheinen kann, bis Sie versuchen, mit Typen zu arbeiten und Typen zu delegieren oder einzuschalten. Schauen Sie sich Folgendes an:

val myList = 1 :: 2 :: "3" :: fred :: Nil

Was ist die Art von myListhier? Wenn Sie es inspizieren würden, würden Sie sehen, dass es vom Typ war List[Any]. Das ist nicht sehr hilfreich. Was noch weniger hilfreich ist, ist, wenn ich versucht habe, Folgendes PartialFunction[Any]zu verwenden, mapum darüber hinwegzukommen:

myList.map{
  case x: Int => x
  case x: String => Int.parseInt(x)
}

Zur Laufzeit kann dies einen auslösen, MatchErrorda ich Ihnen nicht gesagt habe, um welchen Typ es sich fredhandelt. Es könnte vom Typ sein Fred.

Mit einem können HListSie direkt beim Kompilieren feststellen, ob Sie einen der Typen dieser Liste nicht erfasst haben. Wenn ich oben definiert hätte, myList = 1 :: 2 :: "3" :: fred :: HNilwann ich auf das dritte Element zugegriffen habe, wäre dies der Typ, Stringund dies wäre zur Kompilierungszeit bekannt.

Wie @KevinWright feststellt, steckt bei Shapeless noch mehr dahinter, aber es HListist eines der bestimmenden Merkmale der Bibliothek.

Wheaties
quelle
20

Alles in Shapeless hat zwei Dinge gemeinsam:

Erstens ist es nicht in der Scala-Standardbibliothek, sollte es aber wohl sein. Das Fragen, wofür Shapeless ist, ist daher ein bisschen wie das Fragen mit der Scala-Standardbibliothek! Es ist für alles . Es ist eine Wundertüte.

(aber es ist keine völlig willkürliche Wundertüte, weil :)

Zweitens bietet alles in Shapeless mehr Kontrolle und Sicherheit beim Kompilieren . Nichts in Shapeless (woran ich denken kann?) "Tut" zur Laufzeit tatsächlich etwas. Alle interessanten Aktionen finden statt, wenn Ihr Code kompiliert wird. Das Ziel ist immer ein höheres Vertrauen, dass Ihr Code, wenn er überhaupt kompiliert wird, zur Laufzeit nicht abstürzt oder das Falsche tut. (Daher dieser bemerkenswerte Witz: https://twitter.com/mergeconflict/status/304090286659866624 )

Unter https://stackoverflow.com/a/4443972/86485 finden Sie eine schöne Einführung in die Programmierung auf Typebene mit Links zu weiteren Ressourcen .

Seth Tisue
quelle
3
"Erstens ist es nicht in der Scala-Standardbibliothek, sollte es aber wohl sein." Wenn dies jemals passieren würde, würde ich weglaufen ... und schreien.
JayZee
@ JayZee warum sagst du das?
stsatlantis
1
Lassen Sie mich einen Vergleich versuchen ... Wenn Sicherheit vom Typ Scala Vegetarismus ist, ist Veganismus formlos! Es fügt eine zusätzliche Ebene der Typensicherheit hinzu, die meiner Meinung nach die bereits komplizierte Lebensdauer des Scalac-Compilers verkompliziert. Formlos erfordert mehr Implikits und mehr Typklassen. Ich bin kein Super-Experte für Scala-Kompilierung, aber der Preis, den Sie mit Shapeless zahlen, ist, dass der Compiler mit Shapeless härtere Zeiten haben wird (zumindest ist es meine Erfahrung) und langsamer wird. Ich bevorzuge ein paar "isInstanceOf", drücke manchmal ClassCastException und fix, anstatt mich auf die Magie unter Shapeless zu verlassen.
JayZee
Bedenken Sie auch, dass es selbst Ihrer IDE schwerer fällt, Schlussfolgerungen zu schreiben oder Ihren Code zu kompilieren, auch wenn dies für Sie möglicherweise kein Problem darstellt.
JayZee
Akzent auf das "wohl".
Seth Tisue