В 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]

но опять же, как статья Гершома Базермана демонстрирует, что вы можете захотеть вложить аппликаторы так же глубоко, как вы можете захотеть вложить монады.