Ответ 1
Я считаю, что есть более глубокая причина. Хотя кажется, что для Alternative
нет канонического набора правил, для того чтобы Alternative
имел смысл, определенно должно быть отношение между Alternative
и его операциями Applicative
(иначе это было бы просто произвольный моноид.)
Этот ответ в Confused значением класса типа Alternative и его отношением к другим типам классов утверждает эти законы
- Правильная дистрибутивность (
<*>
):(f <|> g) <*> a = (f <*> a) <|> (g <*> a)
- Правильное поглощение (для
<*>
):empty <*> a = empty
- Левая дистрибутивность (
fmap
):f <$> (a <|> b) = (f <$> a) <|> (f <$> b)
- Левое поглощение (для
fmap
):f <$> empty = empty
которые имеют для меня большой смысл. Грубо говоря, empty
и <|>
равны pure
и <$>
/<*>
то, что 0 и + равны 1 и *.
Теперь, если мы добавим экземпляр Monoid m => Alternative (Const m)
, который совпадает с таковым для Monoid
/Applicative
, правые законы не выполняются.
Например, 2. сбой, потому что
empty <*> (Const x)
= Const mempty <*> Const x -- by the suggested definition of Alternative
= Const $ mempty `mappend` x -- by the definition of <*> for COnst
= Const x -- by monoid laws
который не равен empty = Const mempty
. Точно так же, 1 не удается, простой пример контрпримера устанавливает f = Const (Sum 1); g = Const (Sum 1) ; a = Const (Sum 1)
.
См. также: