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
экземпляры бесплатно.