Полугруппа / моноид / иерархия классов типов групп в ошибках Haskell
Я пытаюсь создать "иерархию" классов алгебраических типов следующим образом:
class Semigroup a where
(.*) :: a -> a -> a
foldr1 (.*) = foldl1 (.*) -- GHCi error: "`foldr1' is not a (visible) method of class `Semigroup'"
class (Semigroup a) => Monoid a where
identity :: a
(.*) identity = id :: a -> a -- GHCi error: "`.*' is not a (visible) method of class `Monoid'"
class (Monoid a) => Group a where
inverse :: a -> a
Таким образом, группы - моноиды, а моноиды - полугруппы. Однако я получаю ошибки, что классы не могут видеть функции своего родительского класса.
Эти ошибки меня беспокоят, потому что я предположил, что написав (например) class (Semigroup a) => Monoid a
класс Monoid a
сможет увидеть функцию (.*)
, И, кроме того, тип foldr1
в прелюдии нет никаких ограничений, поэтому я предположил, что foldr1
будет работать в этом контексте.
2 ответа
Haskell не позволяет вам объявлять (или применять) уравнения в терминах (как, кажется, вы хотите сделать). Это по очень практической причине: доказательство равенства между произвольными терминами в таком богатом языке программирования, как Хаскелл, неразрешимо. Проверка созданного человеком доказательства часто решаема, но также несколько раздражает необходимость писать и отслеживать эти доказательства во время программирования.
Тем не менее, если вы хотите регулярно заниматься этим, есть языки, которые делают это возможным; термин для поиска "зависимые типы". Например, Coq и Agda, возможно, являются двумя наиболее популярными языками с типизированной зависимостью на данный момент, и каждый из них упростит написание типа, населенного только хорошими, законопослушными полугруппами (или моноидами).
Я не уверен, что ты пытаешься сделать.
Если вы пытаетесь предоставить значение по умолчанию для foldr1
в Semigroup
и значение по умолчанию для (.*)
в Monoid
тогда ты не сможешь
foldr1
определяется в Prelude как функция не-типа, поэтому вы не можете дать ей локальное определение вSemigroup
(.*)
является частьюSemigroup
учебный класс. Вы можете дать его значения вSemigroup
экземпляры, и вы можете дать значение по умолчанию для него вSemigroup
класс, но вы не можете дать его значение вMonoid
класс (илиMonoid
экземпляры)
Если вы пытаетесь предоставить значение по умолчанию для (.*)
в Semigroup
и значение по умолчанию для identity
в Monoid
, то вы используете неправильный синтаксис.
Вместо этого попробуйте что-то вроде
class Semigroup a where
(.*) :: a -> a -> a
(.*) = {-something-}
или же
class Semigroup a where
(.*) :: a -> a -> a
x .* y = {-something-}