2014-12-13 6 views
5

Nach this page auf Existenziale in Haskell zu lesen, war ich gezwungen, die Grenzen dieses Verhalten zu testen, so schrieb ich die Schnipsel folgenden Code:einen Funktionsaufruf in einer existentiellen Typ Auflösen

{-# LANGUAGE ExistentialQuantification #-} 

data Showable = forall a. Show a => MkShowable a 

pack :: Show a => a -> Showable 
pack = MkShowable 

instance Show Showable where 
    show (MkShowable x) = show x 

Der Showable Typ ist sehr ähnlich dem ShowBox Typ, der im oben genannten Link erstellt wurde. Dann habe ich dieses erfundene Beispiel erstellt, um meine Frage zu illustrieren.

showSomething :: Bool -> Showable 
showSomething True = pack 1 
showSomething False = pack "ABC" 

main :: IO() 
main = do 
    x <- getLine 
    let y = read x 
    print $ showSomething y 

Dieser Code (der gut arbeitet) fordert den Benutzer zur Eingabe (die ‚True‘ oder ‚False‘ sein soll), und dann 1 ausdruckt, ob es wahr oder "ABC" ist, wenn es falsch ist.

Aber ich verstehe nicht vollständig, wie das System dies tut. Mathematisch macht es vollkommen Sinn. Aber ich sehe nicht, wie der Computer es lösen kann. Für mich sieht es so aus, als ob das System zur Laufzeit eine Entscheidung darüber trifft, ob 's show Instanz oder String' s show Funktion aufgerufen werden soll, aber das würde die Existenz von etwas wie C++ 's Vtables implizieren, was Haskell meiner Meinung nach nicht hat ein Konzept von.

Meine Frage ist: Wie löst es das? Das System kann nicht im Voraus wissen, ob ich true oder false eingeben werde, so dass es nicht wissen kann, welches show zur Kompilierungszeit aufgerufen wird, aber es funktioniert eindeutig in beiden Fällen.

+2

Yup, Typklassen werden in zusätzliche wörterbuchähnliche Argumente transformiert, die Methodenimplementierungen für konkrete Instanzen enthalten. Dieses Argument wird in jeder Funktion mit 'Showable => 'signatur übergeben. – arrowd

+3

Hier ist ein erstaunliches Video, SPJ spricht darüber: http://www.youtube.com/watch?v=6COvD8oynmI – arrowd

+0

GHC hat etwas _exactly like_ C++ vtables. (Obwohl wir sie im Allgemeinen als "Methodenwörterbücher" bezeichnen.) – MathematicalOrchid

Antwort

6

Eine Möglichkeit zur Implementierung von Typklassen besteht darin, ein Wörterbuch mit Funktionen zu übergeben, die eine Typklasse unter der Haube implementieren. Zum Beispiel einer Funktion mit Unterschrift

f :: Show a => T 

würde in

f' :: (a -> String) -> T 

vom Compiler übersetzt werden und wann immer show innen f verwendet wird, wird es durch das zusätzliche Argument (in Wirklichkeit ersetzt es mehr Funktionen sein, alle, die in Show erklärt werden).

Ähnlich der Datentyp

forall a . Show a => MkShowable a 

würde in

forall a . MkShowable' (a -> String) a 

So übersetzt der transformierte Code könnte wie folgt aussehen:

{-# LANGUAGE ExistentialQuantification #-} 

data Showable' = forall a . MkShowable' (a -> String) a 

pack' :: Show a => a -> Showable' 
pack' = MkShowable' show 

instance Show Showable' where 
    show (MkShowable' f x) = f x 

showSomething :: Bool -> Showable' 
showSomething True = pack' 1 
showSomething False = pack' "ABC" 

Wenn pack genannt wird, die show Umsetzung wird auch an den Konstruktor übergeben damit es bei Bedarf verfügbar ist.

1

Ja. Eine Reihe von Sprachfeatures (die meisten davon Erweiterungen) in Haskell kann so betrachtet werden, als würden viele der Konzepte, die in dem komplexen Monolith einer "Klasse" in OO-Programmierung gebündelt sind, als separate Features implementiert. Existentialtypen mit Typklassenbeschränkungen im Wesentlichen sind Vtables!

Damit show (MkShowable x) ohne weitere Einschränkungen funktioniert, muss MkShowable x genügend Informationen enthalten, um zu wissen, wie zu show x. Also genau das tut es; obwohl es nur ein Feld enthält, enthält es tatsächlich zusätzliche Informationen.

Dies ist im Wesentlichen das gleiche wie, wie eine Funktion foo :: Show a => a; foo x = show x scheint nur einen Parameter zu haben, muss aber tatsächlich genug zusätzliche Informationen erhalten, um zu wissen, wie show x; Es kann nicht "fest verdrahtet" sein, da foo wahrscheinlich bei verschiedenen Typen verwendet wird. Aber wo foo erfordert, dass der Aufrufer diese Informationen von außen weitergibt (und das Typsystem erzwingt dies), enthält ein Showable Wert genau die gleiche Information, um in der Lage zu sein, es für die Weitergabe an Funktionen wie foo zu extrahieren.

So, jetzt mit dieser Einrichtung, anders als ohne ExistentialQuantification das Problem zu wissen, welche show Instanz rufen Sie einfach zwischen zwei Werten des gleichen Typs Auswahl (die ein Show Beispiel für einen unbekannten Typen enthält zusammen mit einem Wert des gleichen Typs), was einfach zu machen ist; Es wird kein kompilierzeitliches Wissen darüber benötigt.

+0

Leider wird kein kompilierbares Wissen davon verwendet, wenn es verfügbar ist. Ich habe einen Fehlerbericht darüber eingereicht, aber leider sieht es so aus, als würde es eine ziemlich große Menge an Umstrukturierungen benötigen, um das Problem zu beheben. – dfeuer

Verwandte Themen