mempty с различным определением в зависимости от того, является ли mempty левым или правым аргументом?

У меня есть следующий тип данных и экземпляр полугруппы:

data Or a b =
  Fst a
  | Snd b deriving (Eq, Show)

instance Semigroup (Or a b) where
  (<>) (Fst a) (Fst b) = Fst b
  (<>) (Snd a) (Fst b) = Snd a
  (<>) (Fst a) (Snd b) = Snd b
  (<>) (Snd a) (Snd b) = Snd a

Я хочу сделать моноидный экземпляр для вышеприведенного типа, но я не вижу, как это сделать. Если я использую следующее определение

instance (Monoid a, Monoid b) => Monoid (Or a b) where
  mempty = (Fst mempty)
  mappend = (<>)

он будет работать на всех парах ввода в <>кроме той, где я mappend

(Fst a) <> mempty

который оценит mempty,

Как мне это исправить, чтобы mempty является действительным? Кажется, что это не может быть сделано без какого-либо нового синтаксиса или концепций, так как это зависит от того, находится ли mempty слева или справа...

1 ответ

Решение

Существует совершенно хорошая (и более простая) полугруппа, которая всегда принимает первый аргумент:

newtype FirstS a = FirstS a
instance Semigroup (FirstS a) where
    a <> b = a

К сожалению, это не моноид, потому что - за исключением тривиального выбора упакованного типа - не существует левой идентичности этой операции. Стандарт First тип патчей FirstS добавив отличительный элемент идентичности, таким образом:

newtype First a = First (Maybe a)
instance Semigroup (First a) where
    First Nothing <> b = b
    a <> First Nothing = a
    a <> b = a -- this clause is exactly as before

Тогда легко написать Monoid Например, выбрав mempty = First Nothing, Вы можете использовать аналогичный трюк, добавив элемент отличительного идентификатора в ваш тип:

data Or a b = Fst a | Snd b | Neither
instance Semigroup (Or a b) where
    Neither <> b = b
    a <> Neither = a
    -- the remainder of the clauses are as before

Это делает выбор mempty = Neither довольно легко.

Этот шаблон так часто полезен, что на самом деле он имеет оболочку нового типа в semigroups, чтобы вы могли также написать этот исправленный тип, используя ваш оригинальный Or a b типа просто Option (Or a b) и получить Semigroup а также Monoid экземпляры бесплатно.

Другие вопросы по тегам