将两个monadic值放入一对并返回

时间:2011-09-24 19:42:22

标签: haskell monads parsec applicative pointfree

我正在玩Parsec,我希望将两个解析器组合成一个结果放入一对,然后将另一个函数提供给解析结果来编写如下内容:

try (pFactor <&> (char '*' *> pTerm) `using` (*))

所以我写了这个:

(<&>) :: (Monad m) => m a -> m b -> m (a, b)
pa <&> pb = do
  a <- pa
  b <- pb
  return (a, b)

using :: (Functor f) => f (a, b) -> (a -> b -> c) -> f c
p `using` f = (uncurry f) <$> p

有什么类似的(&lt;&amp;&gt;)已经在某处实现了吗?或者这可以写成免费的吗?我试过fmap (,),但似乎很难匹配类型。

5 个答案:

答案 0 :(得分:11)

优于<&>liftM2

(,) <$> a <*> b

因为应用风格似乎越来越受欢迎并且非常简洁。对这样的事情使用适用的风格将消除<&>本身的需要,因为它比(,) <$> a <*> b更清晰。

此外,这甚至不需要monad - 它也适用于Applicatives。

答案 1 :(得分:7)

  

有什么类似的(&lt;&amp;&gt;)已经在某处实现了吗?或者这可以自由写点吗?我试过fmap(,),但似乎很难匹配类型。

我现在不在任何地方实施,但<&>应与liftM2 (,)相同。与fmap的区别在于,liftM2二进制函数提升为monad。

答案 2 :(得分:6)

使用applicative样式,不需要将中间结果放入元组中,只需立即应用未经验证的函数即可。只需使用<$><*>“直接”应用此功能。

try ((*) <$> pFactor <*> (char '*' *> pTerm))

一般来说,假设MonadApplicative

的理智实例
do x0 <- m0
   x1 <- m1
   ...
   return $ f x0 x1 ...

相当于

f <$> m0 <*> m1 <*> ...

除了后一种形式更通用,只需要一个Applicative实例。 (所有monad 也应该是应用函子,尽管该语言不强制执行此操作。)

答案 3 :(得分:3)

请注意,如果您从Applicative开始向相反的方向发展,那么您将看到您希望组合解析器的方式非常适合Arrow范例和Arrow parsers实现。 E.g:

import Control.Arrow

(<&>) = (&&&) 

p `using` f = p >>^ uncurry f 

答案 4 :(得分:1)

是的,你可以使用适用的风格,但我不相信你的任何一个问题的答案。

是否有一些已经定义的组合器需要两个任意的monad并将它们的值类型绑定在一对中,然后在上下文中粘贴该对?

不在任何标准套餐中。

你可以免费获得最后一点吗?

我不确定是否有办法使用大于1点的arity来制作一个curried函数。我认为没有。

希望能回答你的问题。