Я искал l aws для Alt
класса типов , который выглядит следующим образом:
class Functor f => Alt f
where
(<!>) :: f a -> f a -> f a
Один из l aws выглядит следующим образом:
<$> left-distributes over <!>: f <$> (a <!> b) = (f <$> a) <!> (f <$> b)
Более подробно это:
fmap f $ (<!>) a b = (<!>) (fmap f a) (fmap f b)
Допустим, мы не выполняем операцию <!>
, то есть предположим, что класс записан так:
class Functor f => Alt f
where
alt :: (f a, f a) -> f a
Мы можем написать комбинатор следующим образом:
mapBoth :: Functor f => (a -> b) -> (f a, f a) -> (f b, f b)
mapBoth f = bimap (fmap f) (fmap f)
Представляет композицию функтора type Pair a = (a, a)
с заданным функтором f
. Таким образом, это само по себе отображение морфизма функтора.
Данный закон теперь можно записать (без изменения его значения) следующим образом:
fmap f . alt = alt . mapBoth f
Обратите внимание, что mapBoth f
простое применение fmap f
к обоим аргументам alt
, как в первоначальном утверждении закона.
Это похоже на требование, что alt
является естественным преобразованием функтора (f -, f -)
в функтор f -
.
Однако разве не возможно, чтобы функция типа alt
не была естественным преобразованием? Как написать «плохую» реализацию alt
, которую проверяет этот тип, но будет отклонено законом?