鉴于部分函数f
和参数列表xs
,我正在寻找定义(x, f(x))
的对f
列表。这似乎是一件很自然的事情,但到目前为止我还没有优雅地表达出来。我想知道在Maybe / Monad / Applicative / ...区域中是否有任何可以帮助的东西?以下是有效的,但似乎有点明确。
import Data.Maybe (mapMaybe)
graph :: (a -> b) -> [a] -> [(a, b)]
graph f = map (\x -> (x, f x))
liftMaybe :: (a, Maybe b) -> Maybe (a, b)
liftMaybe (x, Just y) = Just (x, y)
liftMaybe (_, Nothing) = Nothing
partialgraph :: (a -> Maybe b) -> [a] -> [(a, b)]
partialgraph f = mapMaybe liftMaybe . graph f
liftMaybe
是否存在其他名称?我发现了以下一些重构:
import Control.Monad (ap)
graph' :: (a -> b) -> [a] -> [(a, b)]
graph' = map . ap (,)
liftMaybe' :: (a, Maybe b) -> Maybe (a, b)
liftMaybe' (a, mb) = do
b <- mb
return (a, b)
liftMaybe'' :: (a, Maybe b) -> Maybe (a, b)
liftMaybe'' (a, mb) = fmap ((,) a) mb
liftMaybe''' :: (a, Maybe b) -> Maybe (a, b)
liftMaybe''' = uncurry (fmap . (,))
答案 0 :(得分:12)
最简单的方法可能是使用列表理解:
partialGraph :: (a -> Maybe b) -> [a] -> [(a, b)]
partialGraph f xs = [(x, fx) | (x, Just fx) <- graph f xs]
这利用了列表推导中模式匹配的失败语义:如果模式匹配失败,则跳过该列表元素。 1
例如,
ghci> partialGraph (\x -> if even x then Just $ x `quot` 2 else Nothing) [1..10]
[(2,1),(4,2),(6,3),(8,4),(10,5)]
似乎没有在任何地方定义liftSnd :: Functor f => (a, f b) -> f (a,b)
函数; uncurry $ fmap . (,)
就像你要得到的一样简洁。
如果你定义
preservingF :: Functor f => (a -> f b) -> a -> f (a, b)
preservingF = liftA2 fmap (,)
然后你可以使用这个函数来定义
partialGraph :: (a -> Maybe b) -> [a] -> [(a, b)]
partialGraph = mapMaybe . preservingF
这很优雅,虽然preservingF
的定义有点不透明(特别是如果你内联它)。 2
1 这只是列表monad的fail
(或完全合理的mzero
),它只生成计算[]
2 正如您一直无法找到liftMaybe
,I have been unable to find preservingF
for a long time。
答案 1 :(得分:3)
Hoogle没有为(a,m b) -> m (a,b)
返回任何内容。所以我猜答案是否定的!
我最终在本地实现了很多类似的功能。我能想到的最接近的预定义示例是sequence:
sequence :: Monad m => [m a] -> m [a]
但你仍然可以通过破解你的胜利方式(使用Data.Maybe和Control.Arrow):
graph f xs = map (second fromJust) $ filter (isJust . snd) $ zip xs $ map f xs
答案 2 :(得分:3)
liftMaybe
的最简单定义是
import Data.Traversable (sequenceA)
liftMaybe :: (a, Maybe b) -> Maybe (a, b)
liftMaybe = sequenceA
sequenceA
的文档可以在http://hackage.haskell.org/package/base/docs/Data-Traversable.html找到。
一般类型签名为sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
,但在这种情况下,t
为(,) c
,f
为Maybe
。
另外,partialgraph
可以用traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
表示(也来自Data.Traversable
):
partialgraph :: (a -> Maybe b) -> [a] -> [(a, b)]
partialgraph f = mapMaybe $ \x -> traverse f (x, x)
或者,如果你更喜欢一点点无意义:
partialgraph f = mapMaybe (traverse f . join (,))
编辑:当我写这个答案时,我没有意识到GHC 7.6.3标准库中没有定义所需的Traversable
和Foldable
实例(尽管它们在GHC 7.8中) )。在这里,他们是@robx提供的:
instance Foldable ((,) a) where
foldr f y (u, x) = f x y
instance Traversable ((,) a) where
traverse f (u, x) = (,) u <$> f x