В Haskell есть псевдонимы для (liftM. liftM), (liftM. liftM. liftM) и т. д.?
в Haskell есть ли псевдоним для (liftM . liftM), (liftM . liftM . liftM) и т. д.?
Так что мне не нужно быть таким многословным, например:
(liftM . liftM) (+ 1) [Just 1, Just 2] = [Just 2, Just 3]
(liftM2 . liftM2) (+) [Just 1] [Just 2] = [Just 3]
1 ответов
в базе нет такой вещи, как это, но хорошо сделано для того, чтобы задать самый интересный вопрос для меня о переполнении стека в течение некоторого времени.
функторы и аппликативные функторы закрыты по составу (что, конечно, не относится к монадам в целом, поэтому необходимо для трансформаторов монад), поэтому liftA2.liftA2
и liftM2
обычно liftA2
, особенно теперь Applicative становится суперклассом Монада.
лирическое отступление:
вы можете использовать композицию newtype в данные.Функтор.Составьте пакет чтобы составить аппликатор, но вы можете сделать новые аппликаторы из старых другими способами - я настоятельно рекомендую сообщение Гершома Базермана "абстракция с приложениями" в читателе Comonad для людей, которые хотят понять, насколько красива комбинированная аппликативная структура по сравнению со стеком трансформатора монады - я теперь всегда на lookout для создания вещей просто прикладных, а не монадических, где я могу получить необходимую функциональность. Часто я могу использовать Applicative для объединения всех входных данных в значение, которое я хочу вывести, а затем передать его непосредственно туда, где я
t собирается использовать >>=
.
функции и операторы
конечно, ничто не мешает вам определить ваши собственные функции:
liftliftA2 :: (Applicative f, Applicative g) =>
(a -> b -> c) -> f (g a) -> f (g b) -> f (g c)
liftliftA2 = liftA2.liftA2
но это не намного короче, чем liftA2.liftA2
.
мне нравится ваша идея однако сделайте вложенные прикладные операторы, но переключитесь на увеличение угловых скобок, а не на повторение внутреннего оператора, потому что <**>
столкновения с (<**>) = flip (<*>)
на управление.Applicative, и это более логично.
import Control.Applicative
(<<$>>) :: (Functor f, Functor g) =>
(a -> b) -> f (g a) -> f (g b)
(<<$>>) = fmap.fmap
(<<*>>) :: (Functor m, Applicative m, Applicative n) =>
m (n (a -> b)) -> m (n a) -> m (n b)
mnf <<*>> mna = (<*>) <$> mnf <*> mna
дав
ghci> (+) <<$>> [Just 5] <<*>> [Just 7,Just 10]
[Just 12,Just 15]
и, конечно, вы можете продолжать идти:
(<<<$>>>) :: (Functor f, Functor g, Functor h) =>
(a -> b) -> f (g (h a)) -> f (g (h b))
(<<<$>>>) = fmap.fmap.fmap
(<<<*>>>) :: (Functor l,Functor m, Applicative l, Applicative m, Applicative n) =>
l (m (n (a -> b))) -> l (m (n a)) -> l (m (n b))
lmnf <<<*>>> lmna = (<*>) <<$>> lmnf <<*>> lmna
что позволяет вам делать кажущееся невероятным
ghci> subtract <<<$>>> Right [Just 5,Nothing,Just 10] <<<*>>> Right [Just 100,Just 20]
Right [Just 95,Just 15,Nothing,Nothing,Just 90,Just 10]
но опять же, как статья Гершома Базермана демонстрирует, что вы можете захотеть вложить аппликаторы так же глубоко, как вы можете захотеть вложить монады.