1

我正在阅读一些 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 教程中记得,有一种方法可以使用函子或应用函子来构造计算树,最终可以输入参数以从“函子盒”中获取结果。但是我似乎无法在教程中找到示例。如何“巧妙”地改写上面的内容?

4

2 回答 2

5

将 Applicative 实例用于函数:

parent :: Sheep -> Maybe Sheep
parent = mplus <$> mother <*> father
于 2013-06-10T17:56:20.797 回答
4

非常无分

你可以把它写成

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

这是因为 monad 实例 for (->) t(你可以认为是 meaning (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

出于完全相同的原因。但这是个好消息,因为如果你可以使用liftA2or liftA3etc,你可以使用 awesome<$><*>from来做到这一点Control.Applicative

一般来说,如果你有

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

这可以表达为liftM3 f mx my mz,但更好的是f <$> mx <*> my <*> mz,尤其是 ifmxmyetc 实际上是更复杂的表达,正如我通常发现的那样。<*>并且<*>优先级较低(4),因此大多数时候您不需要括号。

在这种情况下,我们可以有

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

这是无点的。(……只要你认为t -> m a不是重点!)

于 2013-06-10T17:55:55.833 回答