Частично применить 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 как не точка!)

Другие вопросы по тегам