Как создать экземпляр типа класса в haskell?
Я новичок в Хаскеле.
Я смотрю, есть ли способ создать экземпляр типа класса.
Есть ли способ заставить этот код работать без использования данных или нового типа?
type N = ∀n. (n -> n) -> n -> n
instance Printable N where
print :: N -> IO ()
read :: String -> N
Когда я пытаюсь загрузить модуль в GHCi, он говорит мне:
Illegal polymorphic or qualified type: N
In the instance declaration for ‘Printable N’
1 ответ
То, что вы там написали, очень похоже на объявление класса, а не на экземпляр. Возможно, вы имели в виду это?
class Printable n where
print :: n -> IO ()
read :: String -> n
Обратите внимание, что n
должен быть в нижнем регистре, потому что это переменная типа, по которой вы определяете класс. Если вы действительно хотите определить экземпляр, то вы, ну, в частности, создать экземпляр n
с N
:
instance Printable N where
print n = ...
read str = ...
На этом этапе все сигнатуры типов являются фиксированными (из определения класса), и вам нужно написать фактические привязки этих функций, следовательно, это должно быть =
не ::
,
Вопрос в том, зачем вам нужен собственный класс? Это только вызовет конфликт имен со стандартными функциями 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
со всеми стандартными экземплярами, которые идут для целых чисел, конечно так же хорошо...