Создание класса типов в Haskell, но получение ошибки «неоднозначное возникновение»

#haskell #compiler-errors #typeclass

Вопрос:

Я новичок в Хаскелле и в настоящее время пытаюсь понять, как писать свои собственные типовые классы. Это то, что у меня есть до сих пор:

 data Signal = X | O

class Show a where
    show :: a -> String
instance Show Signal where
    show X = "X"
    show O = "O"
 

И когда я пытаюсь это сделать, я получаю ошибку :

 Ambiguous occurrence `Show'
    It could refer to
       either `Prelude.Show',
       or `Main.Show
 

И я не могу понять, почему это происходит, потому что я думал, что весь смысл классов типов в Haskell в том, что это делает возможной перегрузку функций? Заранее спасибо за вашу помощь!

Комментарии:

1. Да, но вы не должны определять класс типов в своем модуле.

2. Тогда где же мне вместо этого определить класс типов?

3. он уже определен в Prelude , вы здесь определяете второй, вот что говорит компилятор: теперь существует два класса типов, поэтому неясно, для какого из них вы определяете экземпляр..

Ответ №1:

И я не могу понять, почему это происходит, потому что я думал, что весь смысл классов типов в Haskell в том, что это делает возможной перегрузку функций?

Это правильно, но здесь вы определяете новый класс типов, Show который конфликтует с тем, который находится в Prelude .

Если вы определяете экземпляр, то неясно, к какому Show классу он относится. К тому, который определен в Prelude (где многие типы являются членами), или тому, который вы определили в своей собственной программе.

Таким образом, вы можете определить это как:

 data Signal = X | O

-- no definition for Show

instance Show Signal where
    show X = "X"
    show O = "O" 

Если вы хотите определить свой собственный класс типов, вы можете работать с:

 import Prelude hiding (Show)

data Signal = X | O

class Show a where
    show :: a -> String

instance Show Signal where
    show X = "X"
    show O = "O" 

но это, вероятно, не очень хорошая идея, поскольку все остальные типы не являются членами нового класса типов, а только членами того, который определен в Prelude .

Таким образом, класс типов можно рассматривать как интерфейс на таких языках, как Java: ваши типы данных могут быть членами класса типов, если они определяют экземпляр, который, таким образом, определяет реализацию методов (здесь show ). Но если два интерфейса имеют одно и то же имя, это не значит, что это один и тот же интерфейс.

Комментарии:

1. Есть ли какой-нибудь способ перезаписать класс типов шоу из Прелюдии?

2. @Rosarosa: вы можете import Prelude hiding (Show) , это предотвратит загрузку Show класса типов, и, таким образом, вы сможете определить свой собственный.

3. @Rosarosa: идея заключается в том, что вы определяете несколько экземпляров для класса типов, а не несколько классов типов с одинаковыми именами.