2016-07-30 5 views
1

Я новичок в Haskell.Как создать экземпляр типа класса в haskell?

Я ищу, если есть способ создать экземпляр типа класса.

Есть ли способ заставить этот код работать без использования данных или newtype?

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’ 
+4

Почему вы не хотите использовать 'newtype'? – ErikR

+0

Если я использую newtype или data, мне нужно написать что-то вроде: 'newtype N = N (n -> n) -> n -> n)', а затем переписать такие функции, как '(+) (N a) (N b) = stuff' вместо '(+) = \ ab -> stuff' без распаковки a или b. – CheeseLollipop

+0

Импедантность лучше всего избегать в текущем GHC. Ни в коем случае, но использовать 'newtype' или' data'. (Также смотрите безопасные принуждения, которые заставляют 'newtype' s намного проще обрабатывать в некоторых случаях). – chi

ответ

5

Что вы написали там выглядит очень похоже объявления класса в, не экземпляр. Возможно, вы это имели в виду?

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 

со всеми стандартными экземплярами, которые приходят для целых чисел, конечно же, как хороший ...

+0

Извините, что я плохо объяснил свой вопрос, но вы все равно ответили правильно, спасибо большое! – CheeseLollipop