Теперь у меня другая проблема:
Другая подзадача говорит мне вывести тип данных из классов.
Я не знаю, как это сравнить. У вас есть идея, и не могли бы вы объяснить ее мне, чтобы я мог понять?
``
Экземпляр Eq, где ...
Пример или где ...
Ваше редактирование делает вопрос едва значимым и, безусловно, отделяет его от уже данных ответов.
В общем, подход к такого рода проблемам заключается в том, чтобы не слишком отвлекаться на механизм классов типов. Я предлагаю вам начать с написания такой функции, как eqCurrency:
eqCurrency :: Currency -> Currency -> Bool
eqCurrency ...
Очевидный следующий шаг — ввести аргументы и выполнить сопоставление с образцом. Например, я бы, наверное, написал:
eqCurrency :: Currency -> Currency -> Bool
eqCurrency (Dollar d1 c1) (Dollar d2 c2) = ...
eqCurrency (Yen y1) (Yen y2) = ...
eqCurrency (Euro d1 c1) (Euro d2 c2) = ...
Далее вам предстоит решить, как проверить равенство для разных видов валюты. Итак, спросите себя, есть ли когда-нибудь случай, когда какая-то сумма в долларах может равняться некоторой сумме в иенах? Если да, напишите кейсы для этого. Если нет, возможно, вы можете просто добавить универсальное совпадение с шаблоном, например
eqCurrency _c1 _c2 = False
Как только вы написали эту функцию и довольны ее поведением, вы можете вставить ее в класс типа:
instance Eq Currency where
(==) = eqCurrency
Вам нужно будет сделать то же самое для класса типа Ord. Для Ord, минимальное полное определение является либо определяющим <=, либо compare, поэтому вам следует выбрать одно из них. Например, вы можете определить:
leqCurrency :: Currency -> Currency -> Bool
leqCurrency ...
Вы снова зададите себе те же вопросы: если у меня есть две суммы Dollar, когда одна меньше другой? Если у меня есть Euro и Yen, какая из них меньше другой? Я не могу ответить вам на эти семантические вопросы, но вы будете использовать свои ответы для кодирования различных случаев, и когда вы закончите, вы сможете заполнить класс типа:
instance Ord Currency where
(<=) = leqCurrency
Я думаю, у вас опечатка - в последнем блоке кода Eq должно быть Ord
Да, спасибо, что поймали!
Я не знаю, как сравнить каждую валюту
И я нет. «Как следует сравнивать валюты» — это скорее вопрос дизайна, чем реализации.
Если вы хотите добиться полной точности, вам придется использовать Интернет для загрузки текущих обменных курсов, чтобы провести сравнение. Но экземпляры Eq и Ord просто не разрешают подключение к Интернету, так что это невозможно.
Похоже, это упражнение, так что, может быть, было бы справедливо выбрать фиксированные обменные курсы для вашей программы? Google сообщает мне, что на момент написания один цент США стоит 1,4 иены, поэтому я согласен с этим.
Тогда мы знаем один случай для ord:
instance Ord Currency where
compare (Dollar dollars cents) (Yen yen) = compare ((dollars*100 + cents) * 1.4) yen
-- ...
Остальная часть экземпляра Ord может быть заполнена аналогичным образом, с вариантами для compare (Yen ...) (Dollar ...) и compare (Dollar ...) (Euro ...) и т. д. и т. д.
Эта реализация будет работать, и ее стоит заполнить полностью.
Однако есть «более чистое» решение, если вам интересно. Мы можем выбрать какую-нибудь «якорную» валюту, скажем, йену. Затем мы можем написать так называемую функцию «нормализации», которая конвертирует каждую валюту в иену:
normalize :: Currency -> Integer
normalize (Dollar dollars cents) = (dollars*100 + cents) * 1.4
-- you fill in the rest
Используя это, мы можем написать Ord проще, как просто
instance Ord Currency where
compare c1 c2 = compare (normalize c1) (normalize c2)
Непонятно, как вы планируете сравнивать доллары с йенами. Должна ли ваша программа получать обменные курсы из Интернета или что-то в этом роде?