flatMap对于列表和Maybe的应用

4

我正在寻找一种可以同时映射和展开List和Maybe的代码。我在这个话题中找到了这样一个flatMap函数:

flatMap :: (t -> [a]) -> [t] -> [a]
flatMap _ [] = []
flatMap f (x:xs) = f x ++ flatMap f xs

这个很好用:

> flatMap id [[],[1,2],[3],[],[4,5,6]]
[1,2,3,4,5,6]

唯一的问题是它不适用于Maybes。相反,我必须使用Data.Maybe.mapMaybe:
> Data.Maybe.mapMaybe id [Just 1, Nothing, Just 2, Just 3, Nothing]
[1,2,3]

有没有一个内置函数可以处理列表(Lists)和可能性(Maybes)(以及可能的其他类型)?

当你知道你拥有什么时,你可以使用 catMaybes :: [Maybe a] -> [a]concat :: [[a]] -> [a],再配合 map :: (a -> b) -> [a] -> [b] 使用。 - rampion
1个回答

11

我认为Data.Foldable可能是你在寻找的内容:

> let flatMap f = concatMap (Data.Foldable.toList . f)
> :t flatMap
flatMap :: Data.Foldable.Foldable t => (a -> t b) -> [a] -> [b]
> flatMap id [[],[1,2],[3],[],[4,5,6]]
[1,2,3,4,5,6]
> flatMap id [Just 1, Nothing, Just 2, Just 3, Nothing]
[1,2,3]

8
Data.Foldable中已经有了一个用于此的函数,名为foldMap - dflemstr
@dflemstr: 如何使用 Maybe 让它正常工作?foldMap id [Just 1] 会产生错误。 - kiritsuku
因此,在Haskell中,如果附加两个“ Just”,则不会丢弃第二个元素(就像在Scala中一样); Just中的元素将被附加。由于无法附加“ Int”,因此您的代码失败了。如果要返回列表,则需要将“ id”替换为“ toList”。您还可以创建一个新的类似Maybe的类型,当附加内容时,它的行为方式与Scala的Option相同。最后,您可以跳过使用Maybe,而只是使用一个元素的列表,这并不算太糟糕。 - dflemstr
@dflemstr:感谢您详细的解释。我想我明白了。我改变了我的代码,以使用列表和=<<而不是Maybes。 - kiritsuku
1
在Haskell中,“appending”在这个上下文中(在Monoid或Semigroup的意义上)表示任何可结合的操作。对于Maybemappend(Just(Sum 1))(Just(Sum 2))== Just(mappend(Sum 1)(Sum 2))== Just(Sum 3)。您提供的操作不会作为mappend的可能实现进行类型检查(类型为mappend :: Monoid m => m -> m -> m)。现在,请注意,有三种可能的实现可以进行类型检查并且是可结合的。其他两个提供为“First”和“Last”“newtype”。catMaybes :: [Maybe a] -> [a]与您所描述的类似。 - David Young
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接