2013-04-04 3 views
8

Предположим, что у меня есть следующий класс:Haskell классы наследовании типа

class P a where 
    nameOf :: a -> String 

Я хотел бы заявить, что все экземпляры этого класса автоматически экземпляры Show. Моя первая попытка будет следующее:

instance P a => Show a where 
    show = nameOf 

Моя первая попытка пойти по этому пути вчера привело к кроличьим лабиринтом расширений языка: Я первый сказал, чтобы переключиться на гибких случаях, то неразрешимые случаи, то перекрывающихся экземпляров, и, наконец, получить сообщение об ошибках перекрытия экземпляров. Я сдался и вернулся к повторению кода. Однако это принципиально похоже на очень простой спрос, и тот, который должен быть легко удовлетворен.

Итак, два вопроса:

  1. Есть тривиальным простой способ сделать это, что я просто пропустил?
  2. Почему возникает проблема с перекрывающимися экземплярами? Я могу понять, почему мне может понадобиться UndecidableInstances, так как я, кажется, нарушаю условие Патерсона, но здесь нет перекрывающихся экземпляров: экземпляров P нет. Почему typechecker полагает, что существует несколько экземпляров для Show Double (как кажется в этом примере с игрушкой)?
+3

Перекрытие (и разрешение перегрузки) определяется только головой экземпляра 'Show a', поэтому он действительно перекрывается с любым другим экземпляром Show. – augustss

+1

Предположим, вы объявили экземпляр 'P Int', и у вас уже был экземпляр для' Show Int', поэтому это приведет к перекрытию экземпляров Show. – Satvik

+0

@Satvik Конечно, кроме того, что у меня нет экземпляра 'P Int'. Я ожидал бы ошибку, если бы попытался создать 'P Int', но не просто объявив, что он может существовать. – Impredicative

ответ

5

Вы получаете перекрывающуюся ошибку экземпляров, потому что некоторые из ваших экземпляров P могут иметь другие экземпляры Show и тогда компилятор не сможет решить, какие из них использовать. Если у вас есть экземпляр P для Double, то вы идете, вы получаете два экземпляра Show для Double: ваш общий и тот, который уже объявлен в базовой библиотеке Haskell. Как эта ошибка срабатывает, корректно указывается @augustss в комментариях к вашему вопросу. Для получения дополнительной информации см. the specs.

Как вы уже знаете, нет способа достичь того, что вы пытаетесь без UndecidableInstances. Когда вы включаете этот флаг, вы должны понимать, что вы берете на себя ответственность компилятора, чтобы гарантировать, что не возникнут конфликтующие экземпляры. Это означает, что, конечно, не должно быть никаких других экземпляров Show, созданных в вашей библиотеке. Это также означает, что ваша библиотека не будет экспортировать класс P, что приведет к стиранию возможности библиотеки библиотеки, объявляющей конфликтующие экземпляры.

Если ваш случай каким-то образом противоречит сказанному выше, это надежный признак того, что с ним что-то не так. И на самом деле существует ...


То, что вы пытаетесь достичь, является неправильным, прежде всего. У вас не хватает нескольких важных моментов, о Show класса типов, отличающие его от конструкций, как toString метод популярных языков OO:

  1. От Show's haddock:

    Результатом шоу является синтаксически правильное выражение Haskell содержащие только константы, с учетом объявлений фиксированности, действующих в точке, где объявлен тип. Он содержит только имена конструкторов, определенные в типе данных, круглых скобках и пробелах.При использовании меток полей конструктора используются также скобки, запятые, имена полей и знаки равенства.

    Другими словами, объявление экземпляра Show, которое не производит действительного выражения Haskell, является само по себе неправильным.

  2. Учитывая вышеизложенное, просто не имеет смысла объявлять пользовательский экземпляр Show, когда тип позволяет просто получить его.

  3. Если тип не позволяет получить его (например, GADT), обычно вам все равно придется придерживаться экземпляров конкретных типов для получения правильных результатов.

Так что, если вам нужна функция пользовательского представления, вы не должны использовать Show для этого. Просто объявите пользовательский класс, например:

class Repr a where 
    repr :: a -> String 

и ответьте на заявление об ответственности ответственно.

+0

Я опасаюсь принять этот ответ, потому что я чувствую, что это технически неправильно частично. Проблема заключается не в том, что некоторые экземпляры 'P' имеют другие экземпляры' Show': как отмечено, там * нет * экземпляров 'P'. 'augustss' объяснил истинную проблему, имея в виду, как оценивается совпадение. Если вы это исправите, я буду рад принять; Я говорю вам об использовании «шоу». – Impredicative

+0

@Impredicative Вероятно, я не уточнил, я обновил первый абзац. –

Смежные вопросы