我刚刚编写了这个函数,它只需要一对第二个值在一些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,)
谢谢!
答案 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。