部分应用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教程中,有一种方法可以使用函子或应用函子来构建计算树,最终可以提供参数以从"函子盒"中获得结果。然而,我似乎找不到教程中的例子。我如何"巧妙地"重写上面的内容?

为函数使用application实例:

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

非常无点

可以写成

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)

但是为什么使用Monad当你可以有更好的应用程序?

或者为什么我偷了hammar的好答案:

现在,有一个适用于(->) 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不是一个点!)

最新更新