部分应用mplus以无点样式重写功能

时间:2013-06-10 17:49:53

标签: haskell applicative

我正在阅读一些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 个答案:

答案 0 :(得分:5)

使用Applicative实例进行功能:

parent :: Sheep -> Maybe Sheep
parent = mplus <$> mother <*> father

答案 1 :(得分:4)

非常无点

你可以把它写成

partialPlus :: MonadPlus m => (t -> m a) -> (t -> m a) -> t -> m a
partialPlus = liftM2 mplus

这是因为(->) t的monad实例(您可以将其视为(t ->)的意思。

更详细的类型:

liftM2 :: Monad func_t => (a -> b -> c) -> func_t a -> func_t b -> func_t c

给予高度偏见的名称func_t以建议从t到...的功能

那么

liftM2 mplus :: (Monad func_t, MonadPlus m) => func_t (m a) -> func_t (m a) -> func_t (m a)

但是为什么在你可以拥有更好的Applicative时使用Monad?

或者为什么我偷了哈马尔的好答案:

现在,(->) t有一个应用实例,所以我们也可以编写

partialPlus = liftA2 mplus

其原因完全相同。但这是个好消息,因为如果您可以使用liftA2liftA3等,则可以使用来自<$>的精彩<*>Control.Applicative

一般来说,如果你有

this = do
  x <- mx
  y <- my
  z <- mz
  return (f x y z)

可以表达为liftM3 f mx my mz,但更好地表达为f <$> mx <*> my <*> mz,特别是如果mxmy等实际上更复杂的表达,正如我常常发现的那样。 <*><*>的优先级较低(4),所以大部分时间都不需要括号。

在这种情况下,我们可以

partialPlus f1 f2 = mplus <$> f1 <*> f2

这是无点的。 (...只要你认为t -> m a不是一个观点!)