2016-07-30 23 views
1

Ich bin ein Neuling in Haskell.Wie erstellt man eine Typinstanz der Klasse in Haskell?

Ich suche, ob es eine Möglichkeit gibt, eine Instanz des Typs einer Klasse zu erstellen.

Gibt es eine Möglichkeit, diesen Code ohne Verwendung von Daten oder Newtype funktionieren zu lassen?

type N = ∀n. (n -> n) -> n -> n 

instance Printable N where 
     print :: N -> IO() 
     read :: String -> N 

Wenn ich versuche, das Modul in GHCi es mir sagt, zu laden:, keine Instanz

Illegal polymorphic or qualified type: N 
In the instance declaration for ‘Printable N’ 
+4

Warum Sie nicht verwenden möchten 'newtype'? – ErikR

+0

Wenn ich newtype oder Daten verwende, muss ich etwas schreiben wie: 'newtype N = N (n -> n) -> n -> n)' und schreibe dann Funktionen wie '(+) (Na) (N b) = stuff 'anstelle von' (+) = \ ab -> stuff 'ohne unboxing a oder b. – CheeseLollipop

+0

Im aktuellen GHC sollte die Imprädiktivität vermieden werden. Umsonst, aber um 'newtype' oder' data' zu verwenden. (Achten Sie auch auf sichere Zwänge, wodurch 'newtype' in manchen Fällen einfacher zu handhaben ist). – chi

Antwort

5

Was haben Sie es geschrieben viel wie eine Klassendeklaration sieht. Vielleicht hast du das gemeint?

class Printable n where 
    print :: n -> IO() 
    read :: String -> n 

Beachten Sie, dass die n Klein sein muss, denn das ist die Variable vom Typ Sie die Klasse über sind quantisiert. Wenn Sie tatsächlich eine Instanz definieren möchten, dann sind Sie, na ja, instanziiert n mit N:

instance Printable N where 
    print n = ... 
    read str = ... 

An dieser Stelle die Typ Signaturen alle fest sind (von der Klassendefinition) und was Sie brauchen, um schreiben sind die tatsächlichen Bindungen dieser Funktionen, daher muss es =, nicht :: sein.

Frage ist: warum brauchen Sie überhaupt Ihre eigene Klasse? Es wird nur Namenskonflikte mit den Standardfunktionen print und read verursachen, die bereits im Vorspiel sind. Was sollten Sie eigentlich tun diese Standardklassen mit Ihrem N Typ instanziiert, dh

instance Show N where 
    show n = ... 
instance Read N where 
    readsPrec _ str = ... 

Das heißt, auf die eigentliche Frage bekommen Sie gefragt haben: kein, ist es nicht möglich, zu definieren, beliebig Instanzen sinnvoll für einen polymorphen Typ wie ∀ n . (n->n) -> n->n. Wie soll der Compiler dies von spezifischeren Typen wie (Int->Int) -> Int->Int oder allgemeineren wie ∀ n m . (n->m) -> n->m unterscheiden? Es ist ziemlich hoffnungslos. Die korrekte Sache zu tun ist, wickeln Sie es einfach in einen neuen Typ; das verbirgt die universelle Quantifizierung und erlaubt dem Compiler, N von anderen Typen richtig zu unterscheiden.

Alternativ können Sie nur monomorphic Funktionen schreiben, die/Ertrag akzeptieren N direkt:

showChurch :: N -> String 
showChurch n = ... 
readsPrecChurch :: Int -> ReadS N 
readsPrecChurch _ str = ... 

Eigentlich ist letzteres schon zu viel für den Typ-System: die ReadS N ist die Abkürzung für

readsPrecChurch :: Int -> String -> [(∀ n . (n->n) -> n->n, String)] 

universelle Quantifizierung innerhalb einer Liste? Oh oh. Das ist ein impredikativer Typ. GHC hat eine -XImpredicativeTypes Erweiterung, aber es funktioniert nicht wirklich.

Vermeiden Sie einfach diese Probleme, indem Sie polymorphe Typen nicht offen verwenden.Es gibt ein paar großartige Verwendungen für Rank-N-Typen (insbesondere Objektive), aber die meiste Zeit sind sie völlig übertrieben und unnötig. Es gibt sicher keinen Grund, Kirchenziffern so zu benutzen.

newtype N = Church { getChurch :: ∀ n . (n->n) -> n->n } 

können Sie beliebige Instanzen oder Funktionen ohne Problem zu definieren. Und praktisch gesehen, einfach

type N = Int 

mit allen Standard-Instanzen zu tun, die für ganze Zahlen kommen, ist natürlich nur so gut ...

+0

Entschuldigung, ich habe meine Frage schlecht erklärt, aber Sie haben immer noch richtig geantwortet, vielen Dank! – CheeseLollipop