【问题标题】:Understanding this matrix transposition function in Haskell在 Haskell 中理解这个矩阵转置函数
【发布时间】:2011-02-04 10:55:51
【问题描述】:

这个矩阵转置函数有效,但我试图逐步理解它的执行,但我不明白。

    transpose:: [[a]]->[[a]]
    transpose ([]:_) = []
    transpose x = (map head x) : transpose (map tail x)

transpose [[1,2,3],[4,5,6],[7,8,9]]

它返回:

 [[1,4,7],[2,5,8],[3,6,9]]

我不明白串联运算符是如何处理地图的。它在同一个函数调用中连接 x 的每个头部?怎么样?

这是吗

(map head x)

为每个列表的头元素创建一个列表?

【问题讨论】:

  • 这不是一个答案,但通常当我试图在 Haskell 中解决某些问题时,我会花一些时间在 GHCi 中玩弄它。在几个列表列表上尝试“map head”或“map tail”,您将亲眼看到它们是如何工作的。如果您来自命令式世界,地图和折叠可能有点难以理解。它们是你的主要循环结构——基本上取代了“for”和“while”——所以你很快就会学会喜欢它们。

标签: algorithm list haskell


【解决方案1】:

让我们看看该函数对您的示例输入做了什么:

transpose [[1,2,3],[4,5,6],[7,8,9]]
<=>
(map head [[1,2,3],[4,5,6],[7,8,9]]) : (transpose (map tail [[1,2,3],[4,5,6],[7,8,9]]))
<=>
[1,4,7] : (transpose [[2,3],[5,6],[8,9]])
<=>
[1,4,7] : (map head [[2,3],[5,6],[8,9]]) : (transpose (map tail [[2,3],[5,6],[8,9]]))
<=>
[1,4,7] : [2,5,8] : (transpose [[3],[6],[9]])
<=>
[1,4,7] : [2,5,8] : (map head [[3],[6],[9]]) : (transpose (map tail [[3],[6],[9]]))
<=>
[1,4,7] : [2,5,8] : [3, 6, 9] : (transpose [[], [], []])
<=>
[1,4,7] : [2,5,8] : [3, 6, 9] : [] -- because transpose ([]:_) = []
<=>
[[1,4,7],[2,5,8],[3,6,9]]

请注意,我选择减少术语的顺序与 haskell 将使用的评估顺序不同,但这不会改变结果。

编辑:针对您编辑的问题:

这是

(map head x)

为每个列表的头元素创建一个列表?

是的。

【讨论】:

  • 你当时用的是调试器吗?
  • 可能是他自己写的吧?写起来也不算复杂。
  • () 没有创建列表。 map 位于 () 内部,transpose 都创建列表。
  • @dmindreader: () 是 Unit,它不会出现在代码中的任何位置。 [] 是空列表。
【解决方案2】:

cons 运算符:a 类型的对象附加到[a] 类型的列表中。在

(map head x) : transpose (map tail x)

LHS 是一个列表 (a = [b]),而 RHS 是一个列表列表 ([a] = [[b]]),所以这样的构造是有效的。结果是

[x,y,z,...] : [[a,b,...],[d,e,...],...] = [[x,y,z,...], [a,b,...],[d,e,...],...]

在您的情况下,map head xmap tail x 拆分矩阵

x = [[1,2,3],[4,5,6],[7,8,9]]

进入

map head x = [1,4,7]
map tail x = [[2,3],[5,6],[8,9]]

(是的,map head x 是每个列表的头元素的列表。)第二部分被转置(有关详细步骤,请参阅@sepp2k 的答案)以形成

transpose (map tail x) = [[2,5,8],[3,6,9]]

所以 cons-ing [1,4,7] 这给了

map head x : transpose (map tail x) =  [1,4,7] : [[2,5,8],[3,6,9]]
                                    = [[1,4,7] ,  [2,5,8],[3,6,9]]

【讨论】:

    【解决方案3】:

    ghci是你的朋友:

    *Main> :t 地图头
    地图头 :: [[a]] -> [a]
    *Main> :t 地图尾部
    地图尾 :: [[a]] -> [[a]]

    即使您不理解map(您想快速纠正的问题!),这些表达式的类型也能说明它们是如何工作的。第一个是从列表列表中提取的单个列表,所以让我们向它提供一个简单的向量,看看会发生什么。

    你可能想写

    *Main> map head [1,2,3]
    

    但无法进行类型检查:

    :1:14:
        (Num [a]) 没有实例
          来自于 :1:14 的文字 '3'
        可能的解决方法:为 (Num [a]) 添加一个实例声明
        在表达式中:3
        在 `map' 的第二个参数中,即 `[1, 2, 3]'
        表达式中:map head [1, 2, 3]

    记住,参数的类型是列表的列表,所以

    *Main> map head [[1,2,3]]
    [1]
    

    有点复杂

    *Main> map head [[1,2,3],[4,5,6]]
    [1,4]
    

    做同样的事情,但使用tail 而不是head 给出

    *Main> map tail [[1,2,3],[4,5,6]]
    [[2,3],[5,6]]
    

    如您所见,transpose 的定义是用map head x 重复切掉第一“行”并转置其余部分,即map tail x

    【讨论】:

      【解决方案4】:

      这些东西都是一样的:

      map head xxs
      map (\xs -> head xs) xxs
      

      这是 lambda 表达式,这意味着我为每个 xs 返回 xs 的头部 示例:

         map head [[1,2,3],[4,5,6],[7,8,9]]
      -> map (\xs -> head xs) [[1,2,3],[4,5,6],[7,8,9]]
      -> [head [1,2,3], head [4,5,6], head [7,8,9]]
      -> [1,4,7]
      

      很简单

      【讨论】:

        【解决方案5】:

        顺便说一下,当给定[[1,2,3], [], [1,2]] 之类的输入时,此功能不起作用。但是,来自Data.List 的转置函数将接受此输入,并返回[[1,1], [2,2], [3]]

        当我们调用递归的transpose代码时,我们需要去掉[]

        【讨论】:

        • 最好把这个放到实际答案的cmets中;发帖人不只是试图调用转置,而是想弄清楚它为什么起作用。
        【解决方案6】:

        如果您想使用headtail 转置矩形 数组,并确保事先确保列数相同,则可以执行以下操作:

        rectangularTranspose :: [[a]] -> [[a]]
        rectangularTranspose m = rectTrans m []
          where
            rectTrans [] a = a
            rectTrans ([]:xss) a = rectTrans xss a
            rectTrans ((x:xs):xss) a = rectTrans a ((x:map head xss): rectTrans (xs:map tail xss) a)
        

        显然,它也适用于方形数组和单例,但当标准实现为您提供更多选择时,我认为它没有多大用处。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-06-21
          • 2012-01-12
          • 1970-01-01
          • 2013-03-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-05
          相关资源
          最近更新 更多