解析模式中的错误:xs - 理解

时间:2014-05-14 21:18:05

标签: haskell pattern-matching parse-error

我在haskell中有以下两个函数:

plusList :: [[Int]] -> [Int]
plusList [xs ys] = add xs + plusList [ys]
plusList [[]] = 0


add::[Int] -> Int
add (x:xs) = x + add xs
add [] = 0

所以,我认为我在plusList中有错误[xs ys] =添加xs + plusList ys

我的想法是通过设置集合,即[[Int]],通过取第一个List xs,在其上应用“add”,然后用“plusList ys”递归调用第二个列表ys

我是哈斯克尔的新手,我可以这样做吗?如果不是,为什么?

1 个答案:

答案 0 :(得分:10)

你当然可以在Haskell中做你想做的事,但你的语法错了。您的add功能正确,但plusList不正确。特别是,语法[xs ys]作为Haskell的模式没有意义,你可能想要

plusList (xs:ys) = add xs + plusList ys

请注意这与add完全相同的模式?虽然,根据您的类型签名,很难说出您想要的是什么。该类型表示返回Int的列表,但您的函数正文表示只返回Int。如果你想要前者,可以用

来实现
plusList (xs:ys) = add xs : plusList ys

但这正是map add!如果您想要后者,请使用上面的第一个片段。

你遇到的第二个问题是

plusList [[]] = 0

这是一个完全有效且合法的Haskell代码行,但它不会做你想要的。你看,[] :: [[Int]][[]] :: [[Int]]之间存在差异。第一个是Int个列表的空列表,第二个是包含Int个空列表的列表。如果您运行length ([] :: [[Int]]),则会获得0,但对于length ([[]] :: [[Int]]),您将获得1!相反,只需做

plusList [] = 0

同样,这与add中的模式完全相同。如果您希望plusList返回[Int],则此行应为

plusList [] = []

所以我们有两个版本

plusList :: [[Int]] -> Int
plusList (xs:ys) = add xs + plusList ys
plusList [] = 0

plusList :: [[Int]] -> [Int]
plusList (xs:ys) = add xs : plusList ys
plusList [] = []
-- or just
-- plusList xs = map add xs

但是,有一种更简单的方法可以做到这一点。首先,add仅仅是内置的sum函数,但专门用于Int。但是,内置的sum效率不高,因为它使用foldl。相反,您可以使用

实现更快的变体
add :: [Int] -> [Int]
add xs = foldr (+) 0 xs

foldrfoldl函数概括了您使用的递归类型,因为它是函数式编程中的常见模式。您可以提供将下一个值和累加器组合在一起的函数,初始累加器值和要累积的值,而不是对整个列表进行操作。在您的情况下,累加器与您的值具有相同的类型,这是很常见的。 foldlfoldr之间的差异是微妙的,它们的实现看起来很相似,但Haskell的懒惰意味着foldl可能有空间泄漏和效率问题(那里有很多解释为什么,当你到达那里时查找它。)

此外,如果要对列表列表求和,可以使用高阶函数

来完成
plusList = add . map add

不需要额外的东西,没有匹配的模式,更不用说出错的语法。