Что вы написали там выглядит очень похоже объявления класса в, не экземпляр. Возможно, вы это имели в виду?
class Printable n where
print :: n -> IO()
read :: String -> n
Обратите внимание, что n
должен быть в нижнем регистре, потому что это переменная типа вы квантования класс старше. Если вы действительно хотите, чтобы определить экземпляр, то вы, ну, экземплярn
с N
:
instance Printable N where
print n = ...
read str = ...
На данный момент сигнатуры типов все фиксированные (из определения класса) и то, что вам нужно write - это фактические привязки этих функций, следовательно, это должно быть =
, а не ::
.
Вопрос: зачем вам нужен ваш собственный класс? Это только вызовет столкновения имен со стандартными функциями print
и read
, которые уже находятся в прелюдии. То, что вы на самом деле должны делать это экземпляр эти стандартные классы с N
типа, т.е.
instance Show N where
show n = ...
instance Read N where
readsPrec _ str = ...
Тем не менее, чтобы добраться до фактического вопроса вы спросили: нет, не представляется возможным определить любые экземпляры разумно для полиморфного типа, такого как ∀ n . (n->n) -> n->n
. Как компилятор должен отличать это от более конкретных типов, таких как (Int->Int) -> Int->Int
или более общих, таких как ∀ n m . (n->m) -> n->m
? Это довольно безнадежно. правильно что нужно сделать, это просто обернуть его в новый тип; который скрывает универсальную количественную оценку и позволяет компилятору правильно отличать N
от других типов.
В качестве альтернативы, вы можете просто написать мономорфные функции, которые принимают/выход N
непосредственно:
showChurch :: N -> String
showChurch n = ...
readsPrecChurch :: Int -> ReadS N
readsPrecChurch _ str = ...
Собственно говоря, этот один уже слишком много для системы типа: ReadS N
коротка для
readsPrecChurch :: Int -> String -> [(∀ n . (n->n) -> n->n, String)]
универсальное количественное определение в списке? О, о. Это непроизводительный тип. GHC имеет расширение -XImpredicativeTypes
, но на самом деле это не работает.
Опять же, избегайте этих проблем, не открыто используя полиморфные типы.Существует несколько отличных применений для типов Rank-N (особенно линз), но большую часть времени они полностью переполнены и ненужны. Разумеется, никогда не было веских оснований фактически использовать такие церковные цифры.
newtype N = Church { getChurch :: ∀ n . (n->n) -> n->n }
позволит вам определить произвольные экземпляры или функции без проблем. И, собственно говоря, просто делает
type N = Int
со всеми стандартными экземплярами, которые приходят для целых чисел, конечно же, как хороший ...
Почему вы не хотите использовать 'newtype'? – ErikR
Если я использую newtype или data, мне нужно написать что-то вроде: 'newtype N = N (n -> n) -> n -> n)', а затем переписать такие функции, как '(+) (N a) (N b) = stuff' вместо '(+) = \ ab -> stuff' без распаковки a или b. – CheeseLollipop
Импедантность лучше всего избегать в текущем GHC. Ни в коем случае, но использовать 'newtype' или' data'. (Также смотрите безопасные принуждения, которые заставляют 'newtype' s намного проще обрабатывать в некоторых случаях). – chi