这个简单的Haskell函数是否已经有一个众所周知的名字?

时间:2010-10-22 15:04:33

标签: haskell tuples monads

我刚刚编写了这个函数,它只需要一对第二个值在一些monad中,并“拉出monad”以覆盖整个对。

unSndM :: Monad m => (a, m c) -> m (a, c)
unSndM (x, y) = do y' <- y
                   return (x, y')

是否有更好的和/或更短或无点甚至标准的表达方式?

我已经完成了以下操作,并启用了-XTupleSections ...

unSndM' :: Monad m => (a, m c) -> m (a, c)
unSndM' (x, y) = y >>= return . (x,)

谢谢!

4 个答案:

答案 0 :(得分:13)

如果Traversable的{​​{1}}和Foldable个实例在库中(我想我必须为他们的缺席负责)......

(,) x)

...然后这个(有时称为“强度”)将是instance Traversable ((,) x) where traverse f (x, y) = (,) x <$> f y instance Foldable ((,) x) where foldMap = foldMapDefault 的专业化。

Data.Traversable.sequence

所以

sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)

sequence :: (Monad m) => ((,) x) (m a) -> m (((,) x) a)

事实上,序列并没有真正使用sequence :: (Monad m) => (x, m a) -> m (x, a) 的全部功能:Monad会这样做。此外,在这种情况下,与x配对是线性的,因此Applicative只会traverse而不是<$>pure的其他随机组合,并且(如同已在其他地方指出)你只需要<*>来建立函数结构。

答案 1 :(得分:12)

一个小问题:可以仅使用fmap(无>>=)来编写此内容,因此您实际上只需要一个Functor实例:

unSndM :: (Functor f) => (a, f c) -> f (a, c)
unSndM (x, y) = fmap ((,) x) y

此版本更为通用。要回答有关无点版本的问题,我们可以问pointfree

travis@sidmouth% pointfree "unSndM (x, y) = fmap ((,) x) y"
unSndM = uncurry (fmap . (,))

所以,是的,更短的版本是可能的,但我个人觉得uncurry有点难以阅读并且在大多数情况下都避免使用它。

如果我在自己的代码中编写此函数,我可能会使用<$>中的Control.Applicative,它会删除一个字符:

unSndM :: (Functor f) => (a, f c) -> f (a, c)
unSndM (x, y) = ((,) x) <$> y

<$>只是fmap的同义词,我喜欢它使得这是一种更清晰的函数应用程序。

答案 2 :(得分:8)

我还没有看到它写在任何Haskell库中(尽管它可能属于类别附加),但它通常被称为monad的“张力”。参见:

http://en.wikipedia.org/wiki/Strong_monad

http://comonad.com/reader/2008/deriving-strength-from-laziness/

答案 3 :(得分:3)

Hoogle是你的朋友。如果其中一个标准库有它,那么“Monad m => (a, m b) -> m (a,b)”的hoogle会找到它。请注意,该函数仍然可以在hackage包中,但对于像这样的小函数来说,通常不值得额外的build-dep。