#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