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 ...
Warum Sie nicht verwenden möchten 'newtype'? – ErikR
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
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