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"所以在列表的其余部分上递归这个会有效吗?
提前感谢您提供任何提示。
答案 0 :(得分:3)
请注意,您不必提供类型签名:Haskell编译器可以派生一个。如果您将实现放在文件中:
transposeString ([]:_) = []
transposeString x = (map head x) : transposeString (map tail x)
并在:t
中使用ghci
查询该类型,它会返回:
*Main> :t transposeString
transposeString :: [[b]] -> [[b]]
这很有道理:
[[b]]
是b
元素列表的列表;和map head x
表示x
的元素必须是一个列表([b]
),因为我们执行映射,我们必须将列表嵌套一个额外的级别[[b]]
。 tail
。据我所知,您的实施是正确的。您可以通过说[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])