List 为什么Haskell';数据中的s'transpose'函数。列表是否使用'head'和'tail'?

List 为什么Haskell';数据中的s'transpose'函数。列表是否使用'head'和'tail'?,list,haskell,transpose,nested-lists,definition,List,Haskell,Transpose,Nested Lists,Definition,我刚刚花了一些时间研究了一个问题,我需要以某种方式翻译列表。在成功地解决了这个问题后,我提出了以下解决方案: translate::[[a]]->[[a]] 翻译([]:xss)=[] translate xss=(映射头xss):(translate$map尾xss) 不久之后,我意识到我只是想转置一个矩阵。。。我想“我可能为此浪费了很多时间,因为Haskell的标准库中肯定有一个函数可以完成这样一个常见的操作。”所以我决定检查一下,不出所料我发现Data.List模块包含一个transpo

我刚刚花了一些时间研究了一个问题,我需要以某种方式翻译列表。在成功地解决了这个问题后,我提出了以下解决方案:

translate::[[a]]->[[a]]
翻译([]:xss)=[]
translate xss=(映射头xss):(translate$map尾xss)
不久之后,我意识到我只是想转置一个矩阵。。。我想“我可能为此浪费了很多时间,因为Haskell的标准库中肯定有一个函数可以完成这样一个常见的操作。”所以我决定检查一下,不出所料我发现
Data.List
模块包含一个
transpose
函数

但令我惊讶的是它的定义方式:

transpose               :: [[a]] -> [[a]]
transpose []             = []
transpose ([]   : xss)   = transpose xss
transpose ((x:xs) : xss) = (x : [h | (h:_) <- xss]) : transpose (xs : [ t | (_:t) <- xss])
转置::[[a]]->[[a]]
转置[]=[]
转置([]:xss)=转置xss
转置((x:xs):xss)=(x:[h |(h:))对于空列表,像
head
tail
这样的函数将出错。请注意,如果您写入:

[h | (h:_) <- xss]
因此,如果模式匹配失败,则返回一个
fail”“
值。对于列表,这是空列表:

Prelude> fail "" :: [Int]
[]
这对于我们要转置的非矩形列表非常重要,例如:

Prelude Data.List> transpose [[1,4,2,5],[1,3], [1,9,5,8]]
[[1,1,1],[4,3,9],[2,5],[5,8]]
它将改变:

[ 1 4 2 5]
[ 1 3 ]
[ 1 9 5 8]
致:

然而,如果最终在第三行计算
head
tail
时使用
head
tail
,则会在
[1,3]
列表中崩溃:

Prelude Data.List> transpose' [[1,4,2,5],[1,3], [1,9,5,8]]
[[1,1,1],[4,3,9],[2,*** Exception: Prelude.head: empty list

因为对于空列表,这会出错。如果您在各种输入(即内部列表长度不相等)上尝试,您会键入第一个代码示例(
translate
vs
transpose'
)你会发现它会崩溃,因为
是部分的,这就是为什么库版本使用列表理解隐式删除(非初始)空列表的原因。请注意,
本身是根据模式匹配定义的(与其他所有内容一样)因此,通过直接使用模式匹配,您可以跳过一些间接的操作,直接抓住问题的核心。一般来说,您应该更喜欢模式匹配,并为特定用途保留
,而不是相反。另外两种定义它的方法也适用于锯齿列表和
take 1.map(以1为例)$..((1:未定义):未定义)
,它们是:
trs1[]=[];trs1 xs=concatMap(以1为例)xs:trs1[t |(|:t)[];a->a:trs2(map(drop 1)xs)
。最后一个(
trs2
)确实比第一个效率稍低,因为它不会提前清除空列表(就像第一个一样,就像库版本一样)。谢谢你的回答,非常详细,我完全理解!我想如果我下次更广泛地测试我的代码,我最终会自己找到答案…:)
[1 1 1]
[4 3 9]
[2 5]
[5 8]
Prelude Data.List> transpose' [[1,4,2,5],[1,3], [1,9,5,8]]
[[1,1,1],[4,3,9],[2,*** Exception: Prelude.head: empty list