Как создать экземпляр типа класса в 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

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

Другие вопросы по тегам