What you've written there looks a lot like a class declaration, not an instance. Perhaps you meant this?
class Printable n where
print :: n -> IO ()
read :: String -> n
Note that the n
has to be lowercase, because that's the type variable you're quantising the class over. If you actually want to define an instance, then you, well, instantiate n
with N
:
instance Printable N where
print n = ...
read str = ...
At this point the type signatures are all fixed (from the class definition) and what you need to write are the actual bindings of these functions, hence it must be =
, not ::
.
Question is: why do you need your own class anyway? It's only going to cause name clashes with the standard functions print
and read
that are already in the prelude. What you actually should be doing is instantiate those standard classes with your N
type, i.e.
instance Show N where
show n = ...
instance Read N where
readsPrec _ str = ...
That said, to get to the actual question you've asked: no, it is not possible to define any instances sensibly for a polymorphic type like ∀ n . (n->n) -> n->n
. How is the compiler supposed to distinguish this from more specific types like (Int->Int) -> Int->Int
, or more general ones like ∀ n m . (n->m) -> n->m
? It's pretty hopeless. The correct thing to do is to just wrap it in a newtype; that hides the universal quantification and allows the compiler to properly distinguish N
from other types.
Alternatively, you can just write monomorphic functions that accept/yield N
directly:
showChurch :: N -> String
showChurch n = ...
readsPrecChurch :: Int -> ReadS N
readsPrecChurch _ str = ...
Actually the latter one is already too much for the type system: the ReadS N
is short for
readsPrecChurch :: Int -> String -> [(∀ n . (n->n) -> n->n, String)]
universal quantification within a list? Uh oh. That's an impredicative type. GHC does have an -XImpredicativeTypes
extension, but it doesn't really work.
Again, just avoid these problems by not openly using polymorphic types. There are a few great uses for Rank-N types (notably lenses), but most of the time they're completely overkill and unnecessary. There's certainly never a good reason to actually use church numerals like that.
newtype N = Church { getChurch :: ∀ n . (n->n) -> n->n }
will allow you to define arbitrary instances or functions without problem. And, practically speaking, simply doing
type N = Int
with all the standard instances that come for integers is of course just as good...
newtype
? – ErikRnewtype N = N (n -> n) -> n -> n)
and then rewrite functions like(+) (N a) (N b) = stuff
instead of(+) = \a b -> stuff
without unboxing a or b. – CheeseLollipopnewtype
ordata
. (Also look up safe coercions, which makenewtype
s much simpler to handle in some cases). – chi