Полугруппа / моноид / иерархия классов типов групп в ошибках Haskell - PullRequest
5 голосов
/ 13 июля 2011

Я пытаюсь создать «иерархию» классов алгебраических типов следующим образом:

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 в Prelude не имеет ограничений, поэтому я предположил, что foldr1 будет работать в этом контексте.

Ответы [ 2 ]

5 голосов
/ 14 июля 2011

Haskell не позволяет вам объявлять (или применять) уравнения в терминах (как, кажется, вы хотите сделать). Это по очень практической причине: доказывать равенство между произвольными терминами в таком богатом языке программирования, как Haskell, неразрешимо. Проверка созданного человеком доказательства часто решаема, но также несколько раздражает необходимость писать и отслеживать эти доказательства во время программирования.

Тем не менее, если вы хотите регулярно заниматься такими делами, - это языки, которые делают это возможным; термин для поиска "зависимые типы". Например, Coq и Agda, пожалуй, являются двумя наиболее популярными языками с типизированной зависимостью на данный момент, и каждый из них упростил бы написание типа, населенного только хорошими, законопослушными полугруппами (или моноидами).

4 голосов
/ 13 июля 2011

Я не уверен, что вы пытаетесь сделать.

Если вы пытаетесь указать значение по умолчанию для foldr1 в Semigroup и значение по умолчанию для (.*) вMonoid, тогда вы не можете.

  • foldr1 определен в Prelude как функция не-типа, поэтому вы не можете дать ей локальное определение в Semigroup
  • (.*) является частью класса Semigroup.Вы можете указать его значения в Semigroup экземплярах, а также указать значение по умолчанию для него в классе Semigroup, но вы не можете указать его значение в классе Monoid (или Monoid экземплярах) * 1020.*

Если вы пытаетесь указать значение по умолчанию для (.*) в Semigroup и значение по умолчанию для identity в Monoid, то вы используете неправильный синтаксис.

Вместо этого попробуйте что-то вроде

class Semigroup a where
    (.*) :: a -> a -> a
    (.*) = {-something-}

или

class Semigroup a where
    (.*) :: a -> a -> a
    x .* y = {-something-}
...