Почему этот экземпляр Show в Haskell (Hugs) вызывает ошибку переполнения стека?

#haskell #stack-overflow #polymorphism #hugs

#haskell #переполнение стека #полиморфизм #объятия

Вопрос:

Ниже приведен полиморфный тип данных в Haskell, интерпретируемый Hugs. Я пытаюсь создать экземпляр Show для равенства.

В объявлении экземпляра говорится, что если тип «a» находится в Show, то равенство a находится в Show . Он должен вывести два аргумента конструктора, равные b в форме «a = b».

 data Equality a = Equals a a 

instance (Show a) => Show (Equality a) where
show (Equals a b) = a    " = "    b
 

Тем не менее, ввод чего-либо в объятия, например «(Равенство 9 9)», дает:

ОШИБКА — переполнение стека C

Итак, я попытался сделать отступ в строке «show (равно b) …» с парой пробелов. Я не уверен, в чем будет разница, но просто играл, а затем получил это:

 Inferred type is not general enough
*** Expression    : show
*** Expected type : Show (Equality a) => Equality a -> String
*** Inferred type : Show (Equality [Char]) => Equality [Char] -> String
 

Кто-нибудь может объяснить, почему возникают эти ошибки, или предложить лучший способ реализации этого экземпляра show?

Спасибо!

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

1. В целом это плохая идея: Show предназначен для обеспечения базового механизма сериализации для Haskell, создавая действительный код Haskell (по модулю детали импорта). Если вы хотите выполнить пользовательское форматирование вывода, создайте пользовательскую prettyPrint :: a -> String функцию или аналогичную, возможно, используя библиотеку pretty-printing для сложных выходных данных.

Ответ №1:

Ваш код имеет неверный отступ. Он определяет пустой Show экземпляр:

 instance (Show a) => Show (Equality a) where
 

и отдельная функция верхнего уровня show :

 show (Equals a b) = a    " = "    b
 

типа Equality [Char] -> [Char] . Поэтому, когда вы пытаетесь использовать свой Show экземпляр, выбирается определение по умолчанию show из Show класса. Глядя на код:

 showsPrec _ x s = show x    s
show x          = showsPrec zeroInt x ""
 

вы можете видеть, что значение по умолчанию show определяется в терминах showsPrec , которые, в свою очередь, определяются в терминах show . Это объясняет, почему ваша программа переходит в бесконечный цикл.

Чтобы исправить код, сделайте в нем соответствующий отступ и добавьте пропущенные вызовы show , чтобы исправить ошибку типа (которая связана с тем фактом, что вы не можете объединить произвольный тип a со строкой — сначала вам нужно преобразовать a в строку):

 data Equality a = Equals a a

instance (Show a) => Show (Equality a) where
  show (Equals a b) = show a    " = "    show b
 

Тестирование:

 *Main> show (Equals 9 9)
"9 = 9"
 

Ответ №2:

Отступ имеет значение из-за странной чувствительности Haskell к пробелам. Без отступа компилятор не может определить, что следующий оператор принадлежит where .

Ошибка, которую вы получаете, заключается в том, что полиморфный тип, не имеющий ограничений, не гарантирует этого a и b может быть объединен со строкой » = «. Что, если у вас есть Equals 1 1 . Как бы вы объединили это, не создавая сначала целые строки?

Однако, если сначала вы используете show a и b, все работает, потому show что martials преобразует значения во что-то, что может быть объединено со строкой.

 data Equality a = Equals a a

instance (Show a) => Show (Equality a) where
    show (Equals a b) = (show a)    " = "    (show b)
 

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

1. Ах. Я некоторое время танцевал вокруг этого, но не мог собрать все это вместе. Спасибо за четкий, подробный и примерный ответ.

2. Вы можете безопасно удалить скобки вокруг (show a) и (show b)

3. Я бы не сказал, что правила отступов странные… если эта строка принадлежит чему-либо, сделайте отступ больше!

4. Наверное, я имею в виду, что они «на первый взгляд» странные. Ha. Мне потребовалось несколько дней, чтобы чувствовать себя полностью комфортно, когда мне приходилось делать отступы, когда мне приходилось делать отступы после знака равенства и т. Д. Но по этой мере (из-за моего медленного гроккинга) большая часть Haskell странная. Но хорошо странно!

Ответ №3:

Я думаю, ваша проблема в том, что вы не вызывали функцию show для аргументов a и b . Я сделал это в GHC, но я думаю, что это должно сработать:

 data Equality a = Equals a a 

instance (Show a) => Show (Equality a) where
  show (Equals a b) = show a    " = "    show b
 

Затем:

 > Equals 9 9
9 = 9