Haskell:在字符串列表上进行转置

时间:2016-05-01 02:47:12

标签: haskell recursion

Haskell的新功能和语言到目前为止一直很有趣。我希望得到一个好的暗示,而不是一个答案,因为我正在享受改变思维的Haskell。

问题:我有一个字符串列表,我想转置它们。

let x = ["hello", "world"]

会变成

["hw", "eo", "lr", "ll", "od"]

到目前为止我所拥有的是:

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

我绝对知道类型签名有问题。我的理性是

Let y = ["wow", "top"]
map head y 

返回" wt"所以在列表的其余部分上递归这个会有效吗?

提前感谢您提供任何提示。

3 个答案:

答案 0 :(得分:3)

请注意,您不必提供类型签名:Haskell编译器可以派生一个。如果您将实现放在文件中:

transposeString ([]:_) = []
transposeString x = (map head x) : transposeString (map tail x)

并在:t中使用ghci查询该类型,它会返回:

*Main> :t transposeString 
transposeString :: [[b]] -> [[b]]

这很有道理:

  1. 您转置矩阵,这是一个列表列表。 [[b]]b元素列表的列表;和
  2. 您可以自己从实现中获取它:map head x表示x元素必须是一个列表([b]),因为我们执行映射,我们必须将列表嵌套一个额外的级别[[b]]tail
  3. 也是如此

    据我所知,您的实施是正确的。您可以通过说[b] ~ String来对其进行专门化,从而为String添加类型签名:

    transposeString :: [String] -> [String]
    transposeString ([]:_) = []
    transposeString x = (map head x) : transposeString (map tail x)
    

    这又有意义,因为String ~ [Char]因此b ~ Char。但是在专门化函数类型方面没有太大意义:最好总是使用最通用的类​​型签名。在这种情况下[[b]] -> [[b]]

答案 1 :(得分:2)

有一点需要注意。 tranposeString的类型签名允许接受平面列表作为参数。转换[String]是有效的,因为[String]只是[[Char]],但是当您尝试在transposeString上拨打[Int]时会发生什么?毕竟,类型签名允许它。

另一方面,我问你,鉴于你目前的职能,如果被叫transposeString []会怎样?

答案 2 :(得分:0)

请记住,String默认为[Char]

"abc" == 'a' : 'b' : 'c' : []

您可以在此处使用列表的可遍历性质:

transpose :: [[a]] -> [[a]]
transpose mat = getZipList $ sequenceA $ map ZipList mat

test' = transpose [[1,2,3],[4,5,6],[7,8,9]] -- == [[1,4,7],[2,5,8],[3,6,9]]
test'' = transpose ["abc", "deg", "klm"] -- == ["adk","bel","cgm"]

您还可以在haskell文档中检查transponse的默认实现 https://hackage.haskell.org/package/base-4.12.0.0/docs/src/Data.OldList.html#transpose

transpose               :: [[a]] -> [[a]]
transpose []             = []
transpose ([]   : xss)   = transpose xss
transpose ((x:xs) : xss) = (x : [h | (h:_) <- xss]) : transpose (xs : [ t | (_:t) <- xss])