我知道并热爱我的filter
,map
和reduce
,它们恰好是越来越多纯粹功能性语言的一部分。
我发现自己需要一个类似的功能:类似map
,但不是一对一,而是一对多。
即。原始列表中的一个元素可能会映射到目标列表中的多个元素。
那里已经存在这样的事情,还是我必须自己动手?
答案 0 :(得分:5)
这正是>>=
专门用于列表的内容。
> [1..6] >>= \x -> take (x `mod` 3) [1..]
[1,1,2,1,1,2]
的结果放在一起
> map (\x -> take (x `mod` 3) [1..]) [1..6]
[[1],[1,2],[],[1],[1,2],[]]
答案 1 :(得分:2)
您不必自己动手。这里有许多相关的功能,但我要强调三个。
首先,有concat
function,它已经出现在Prelude(默认情况下加载的标准库)中。当应用于列表列表时,此函数的作用是返回包含子列表的连接内容的列表。
练习:编写您自己的concat :: [[a]] -> [a]
版本。
因此,将concat
与map
一起使用,可以编写此函数:
concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f = concat . map f
...除了你实际上不需要写它,因为它是the Prelude already has it这种常见的模式(比我在这里展示的更通用的类型 - 库版本需要Foldable
,而不仅仅是列表。
最后,还有列表的Monad
实例,可以这样定义:
instance Monad [] where
return a = [a]
as >>= f = concatMap f as
因此>>=
运算符(Monad
类的核心)在处理列表时与concatMap
完全相同。
练习:浏览Data.List
module的文档。弄清楚如何将模块导入代码并使用一些函数。