Частично применить mplus для перезаписи функции в стиле без точек
Я прохожу некоторые уроки по Haskell и пытаюсь познакомиться с языком. Я видел этот пример в учебнике Monad/MonadPlus:
data Sheep = Sheep {name :: String, mother :: Maybe Sheep, father :: Maybe Sheep}
parent :: Sheep -> Maybe Sheep
parent s = mother s `mplus` father s
Я пытался переписать его в стиле без точек (просто как упражнение, не сказав, что вышеупомянутое неправильно или не идиоматично), но я застрял: очевидно, я могу написать пользовательскую функцию
partialPlus :: (MonadPlus m) => (a -> m b) -> (a -> m b) -> a -> m b
partialPlus f1 f2 = \x -> f1 x `mplus` f2 x
а затем использовать
parent = partialPlus mother father
но я, кажется, помню из учебника LYAH, что был способ использовать функторы или аппликативные функторы для построения дерева вычислений, которые в конечном итоге могут быть переданы в качестве аргументов для получения результата из "поля функтора". Однако я не могу найти пример в руководстве. Как мне переписать вышесказанное "умно"?
2 ответа
Использование экземпляра Applicative для функций:
parent :: Sheep -> Maybe Sheep
parent = mplus <$> mother <*> father
Очень бессмысленно
Вы могли бы написать это как
partialPlus :: MonadPlus m => (t -> m a) -> (t -> m a) -> t -> m a
partialPlus = liftM2 mplus
это работает из-за экземпляра монады для (->) t
(о котором вы можете думать как о значении (t ->)
,
Типы более подробно:
liftM2 :: Monad func_t => (a -> b -> c) -> func_t a -> func_t b -> func_t c
Присваивая ему весьма предвзятое имя func_t
предложить функцию от т до...
тогда
liftM2 mplus :: (Monad func_t, MonadPlus m) => func_t (m a) -> func_t (m a) -> func_t (m a)
Но зачем использовать Monad, когда у вас может быть более хороший Applicative?
Или Почему я украл хороший ответ Хаммара:
Теперь есть аппликативный экземпляр для (->) t
и поэтому мы могли бы с таким же успехом написать
partialPlus = liftA2 mplus
который работает по той же причине. Но это хорошая новость, потому что если вы можете использовать liftA2
или же liftA3
и т.д., вы можете сделать это с удивительным <$>
а также <*>
от Control.Applicative
,
В общем, если у вас есть
this = do
x <- mx
y <- my
z <- mz
return (f x y z)
это выражается как liftM3 f mx my mz
, но приятнее как f <$> mx <*> my <*> mz
особенно если mx
а также my
и т.д. на самом деле являются более сложным выражением, как я обычно нахожу. <*>
а также <*>
имеет низкий приоритет (4), поэтому большую часть времени вам не нужны скобки.
В этом случае мы можем иметь
partialPlus f1 f2 = mplus <$> f1 <*> f2
что бессмысленно. (... пока вы считаете t -> m a
как не точка!)