В настоящее время я пытаюсь обернуть голову стилями и экземплярами, и я пока не совсем понимаю их. До сих пор у меня есть два вопроса:
1) Почему необходимо иметь класс типа в сигнатуре функции, когда функция использует некоторую функцию из этого типа. Пример:
f :: (Eq a) => a -> a -> Bool
f a b = a == b
Зачем ставить (Eq a)
в подпись. Если ==
не определено для a
, то почему бы просто не выбросить ошибку при встрече a == b
? В чем смысл объявлять класс типа впереди?
2) Как относятся классы типов и функции перегрузки?
Это невозможно сделать:
data A = A
data B = B
f :: A -> A
f a = a
f :: B -> B
f b = b
Но это можно сделать:
data A = A
data B = B
class F a where
f :: a -> a
instance F A where
f a = a
instance F B where
f b = b
Что с этим связано? Почему у меня нет двух функций с тем же именем, но они работают на разных типах... Исходя из С++, я нахожу это очень странным. Но у меня, вероятно, есть неправильные представления о том, что это на самом деле. но как только я завершу их в эти типы экземпляров класса типа, я могу.
Не стесняйтесь бросать категорию или набирать теоретические слова у меня, так как я изучаю эти предметы параллельно с обучением Haskell, и я подозреваю, что в них есть теоретическая основа для того, как Haskell здесь делает что-то.