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

Haskell 模式中的分析错误:xs-理解,haskell,pattern-matching,parse-error,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]=add xs+plusList ys中有错误 我的想法是遍历集合的集合,即[[Int]],取第一个列表xs,对其

我在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]=add xs+plusList ys中有错误

我的想法是遍历集合的集合,即[[Int]],取第一个列表xs,对其应用“add”,然后用“plusList ys”递归调用第二个列表ys


我是哈斯克尔的新手,我能做到吗?如果没有,为什么?

您当然可以在Haskell中做您想做的事情,但您的语法是错误的。您的
add
函数正确,但
plusList
不正确。特别是,语法
[xs-ys]
对于Haskell来说没有任何意义,您可能需要这样做

plusList (xs:ys) = add xs + plusList ys
请注意,这与添加的模式完全相同?虽然,从你的类型签名很难知道你到底想要什么。类型表示返回
Int
列表,但函数体表示只返回
Int
。如果你想要前者,你可以通过

plusList (xs:ys) = add xs : plusList ys
但这正是地图添加!如果您想要后者,请使用上面的第一个代码段

你的第二个问题是

plusList [[]] = 0
这是一个完全有效和合法的Haskell代码行,但它不会做你想要的。你看,
[]:[[Int]]
[[[]]:[[Int]]]
之间有区别。第一个是
Int
s列表的空列表,第二个是包含
Int
s空列表的列表。如果运行
length([[]]:[[Int]])
,您将得到
0
,但对于
length([[]]:[[Int]])
,您将得到1!。相反,只要去做

plusList [] = 0
同样,这与
add
中的模式完全相同。如果您希望
plusList
返回
[Int]
,那么这一行应该是

plusList [] = []
所以我们有两个版本是

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


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

add :: [Int] -> [Int]
add xs = foldr (+) 0 xs
foldr
foldl
函数概括了您使用的递归类型,因为它是函数式编程中的常见模式。您提供了一个函数,用于将下一个值和累加器、初始累加器值以及要累加的值组合在一起,而不是对整个列表进行操作。在您的例子中,累加器的类型与您的值相同,这是非常常见的。
foldl
foldr
之间的区别很微妙,它们的实现看起来非常相似,但Haskell的懒惰意味着
foldl
可能会出现空间泄漏和效率问题(关于原因有很多解释,请在到达时查找)

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

plusList = add . map add

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

我认为你把
foldr
foldl'
搞混了
foldr
这里仍然会有空间泄漏,尽管我认为只有堆栈空间而不是thunk building(thunk运行之后是堆栈)。
plusList = add . map add