34 Stimmen

Welcher Zusammenhang besteht zwischen unboxed types und strictness?

Unboxed-Typen, wie Int# und strenge Funktionen, wie f (!x) = ... sind etwas anderes, aber ich sehe eine konzeptionelle Ähnlichkeit - sie verbieten Thunks/Laziness in irgendeiner Weise. Wenn Haskell eine strikte Sprache wie Ocaml wäre, wäre jede Funktion strikt und jeder Typ unboxed. Was ist die Beziehung zwischen unboxed Typen und der Erzwingung von Strictness?

42voto

Don Stewart Punkte 136046

Unboxed vs. Boxed Daten

Zur Unterstützung parametrischer Polymorphismus y Faulheit werden Haskell-Datentypen standardmäßig einheitlich als Zeiger auf ein Verschluss auf der Haufen mit einer Struktur wie dieser:

alt text
(fuente: <a href="https://hackage.haskell.org/trac/ghc/raw-attachment/wiki/Commentary/Rts/Storage/HeapObjects/heap-object.png" rel="nofollow noreferrer">haskell.org </a>)

Es handelt sich dabei um "verpackte" Werte. Eine unboxed Objekt wird direkt durch den Wert selbst dargestellt, ohne Umweg oder Abschluss. Int ist verpackt, aber Int# wird ausgepackt.

Faule Werte erfordern eine kastenförmige Darstellung. Für strenge Werte gilt das nicht: Sie können entweder als vollständig ausgewertete Closures auf dem Heap oder als primitive unboxed Strukturen dargestellt werden. Beachten Sie, dass Pointer-Tagging ist eine Optimierung, die wir bei gepackten Objekten verwenden können, um den Konstruktor im Zeiger auf die Schließung zu kodieren.

Das Verhältnis zur Strenge

Normalerweise werden unboxed values von Compilern funktionaler Sprachen ad hoc erzeugt. In Haskell jedoch, unboxed Werte sind etwas Besonderes. Sie:

  1. sie haben eine andere Art, # ;
  2. nur an besonderen Orten verwendet werden können; und
  3. sie sind nicht angehoben, werden also nicht als Zeiger auf einen Heap-Wert dargestellt.

Da sie nicht angehoben sind, sind sie notwendigerweise streng. Die Darstellung von Faulheit ist nicht möglich.

So können bestimmte unboxed Typen, wie Int# , Double# werden auf dem Rechner (in C-Notation) wirklich nur als double oder int dargestellt.

Analyse der Strenge

Unabhängig davon macht GHC Stringenzanalyse von regulären Haskell-Typen. Wenn sich herausstellt, dass die Verwendung eines Wertes strikt ist - d.h. er kann niemals 'undefiniert' sein - kann der Optimierer alle Verwendungen des regulären Typs ersetzen (z.B. Int ) mit einer nicht verpackten ( Int# ), da sie weiß, dass die Verwendung von Int ist immer strikt und wird daher durch den effizienteren (und immer strikten) Typ Int# sicher ist.

Wir können natürlich auch strikte Typen ohne unboxed types haben, z. B. eine polymorphe Liste mit strikten Elementen:

data List a = Empty | Cons !a (List a)

ist streng in seinen Elementen, stellt sie aber nicht als unboxed values dar.

Dies zeigt auch den Fehler auf, den Sie bei den strengen Sprachen gemacht haben, wie OCaml . Sie müssen immer noch Polymorphismus unterstützen, also bieten sie entweder eine einheitliche Darstellung, oder sie spezialisieren Datentypen und Funktionen auf jeden Typ. GHC verwendet standardmäßig eine einheitliche Darstellung, ebenso wie OCaml, obwohl GHC auch Typen und Funktionen spezialisieren jetzt (wie C++-Vorlagen).

18voto

Edward Kmett Punkte 29192

Unboxed-Typen sind notwendigerweise strict, aber nicht alle strict-Werte sind notwendigerweise unboxed.

data Foo a = Foo !a !a

hat zwei strikte Felder

data Bar a = Bar {-# UNPACK #-} !Int !a

hat zwei strikte Felder, aber das erste ist unboxed.

Der Grund, warum unboxed types (notwendigerweise) strikt sind, ist, dass es keinen Platz gibt, um den thunk zu speichern, da sie zu diesem Zeitpunkt nur flache, dumme Daten sind.

10voto

kennytm Punkte 488916

Argumente beliebigen Typs können "strict" gemacht werden, aber die einzigen unboxed Typen, die entsprechende boxed Typen haben, sind Char# , Int# , Word# , Double# y Float# .

Wenn Sie niedrige Sprachen wie C kennen, ist es einfacher zu erklären. Unboxed-Typen sind wie int , double , usw., und die Kästchen-Typen sind wie int* , double* , usw. Wenn Sie eine int Sie kennen bereits den gesamten Wert, wie er im Bitmuster dargestellt ist, und sind daher nicht faul. Sie muss auch streng sein, da alle Werte von int gültig sind und nicht ⊥.

Angesichts einer int* können Sie den Zeiger später dereferenzieren, um den tatsächlichen Wert zu erhalten (also faul), und es ist möglich, ungültige Zeiger zu haben (er enthält ⊥, d. h. nicht streng).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X