Полугруппа / моноид / иерархия классов типов групп в ошибках 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-}
Другие вопросы по тегам