Ich bin kürzlich auf diesen Blog-Beitrag von Brian McKenna gestoßen, der den Zeilenpolymorphismus erklärt. Das schien mir eine wundervolle Idee zu sein, aber dann wurde mir klar, dass es sehr nach begrenztem parametrischem Polymorphismus riecht:
Mit Zeilenpolymorphismus:
sum: {x: int, y: int | rho} -> int
function sum r = r.x + r.y
Mit begrenztem parametrischem Polymorphismus:
sum: forall a <: {x: int, y: int}. a -> int
function sum r = r.x + r.y
Kann jemand die Unterschiede zum Polymorphismus zwischen diesen beiden Ansätzen klären?
programming-languages
semantics
Gartenkopf
quelle
quelle
let f x = x with {sum: x.a + x.b}
mit beiden zu tippen ? Wenn ich das richtig verstehe, können Sie mit dem Zeilenpolymorphismus alle zusätzlichen Felder imx
begrenzten parametrischen Polymorphismus beibehalten, da Sie sagen möchten, dass dies ein Typ ist,forall a <: {x: int, y: int}. a -> a_with_a_new_field_sum
und ich glaube nicht, dass Sie dies ausdrücken könnena_with_a_new_field_sum
.with
Konstrukts ab. Da dies im Artikel nicht dargelegt wurde, habe ich versucht, es zu vermeiden, weil es die Dinge verwirrt.forget
Operator haben, der einen Datensatz aufnimmt und eines seiner Felder entfernt. Zumfun r -> forget x of r
Tippen benötigen Sie wahrscheinlich auch Zeilenpolymorphismus.Antworten:
Es gibt also einige Unterschiede:
Beim Zeilenpolymorphismus haben Sie an einen Namen gebunden , sodass Sie ihn an anderer Stelle verwenden können. Zum Beispiel ist es mit Zeilenpolymorphismus ausdrückbar, aber nicht nur mit begrenztem Polymorphismus. Ebenso können Sie das Löschen von Feldern auf diese Weise ausdrücken : Dies ist ein vollkommen gültiger zeilenpolymorpher Typ, aber durch Subtypisierung kann dies nicht wirklich ausgedrückt werden.ρ
forall rho . rho -> {x : int | rho}
forall rho .{x : int | rho} -> rho
Da Sie mit Zeilenpolymorphismus auf diese Weise Felder hinzufügen und löschen können, funktioniert dies normalerweise mit einer "Stapel" -Semantik, sodass alte Felder beim Hinzufügen neuer gleichnamiger Felder schattiert werden.
Bei der begrenzten Untertypisierung wird die Untertypisierung verwendet. Mit Zeilenpolymorphismus können Sie also keine
x : {x : int, y : int}
Funktion vom Typ als Argument angeben{x : int} ->int
. Aber die meisten Systeme mit begrenzter Subtypisierung hätten auch eine nicht polymorphe Subtypisierung, was dies ermöglichen würde, da die meisten Systeme dies getan haben{x : int} <: {x : int, y : int}
.Die begrenzte Untertypisierung ist tendenziell etwas präziser und flexibler, und die "Stapel" -Semantik des Zeilenpolymorphismus tritt nicht so häufig auf. Inferenz ist jedoch für den Zeilenpolymorphismus viel einfacher und kann ohne Typanmerkungen (z. B. in Elm ) funktionieren , was bei Subtypisierung normalerweise nicht der Fall ist.
quelle