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

use*_*712 0 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
Run Code Online (Sandbox Code Playgroud)

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

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

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

bhe*_*ilr 10

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

plusList (xs:ys) = add xs + plusList ys
Run Code Online (Sandbox Code Playgroud)

请注意这与完全相同的模式add?虽然,根据您的类型签名,很难说出您想要的是什么.类型说返回一个列表Int,但是你的函数体说只返回一个Int.如果你想要前者,你可以实现它

plusList (xs:ys) = add xs : plusList ys
Run Code Online (Sandbox Code Playgroud)

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

你遇到的第二个问题是

plusList [[]] = 0
Run Code Online (Sandbox Code Playgroud)

这是一个完全有效且合法的Haskell代码行,但它不会做你想要的.你看,[] :: [[Int]]和之间有区别[[]] :: [[Int]].第一个是Ints 列表的空列表,第二个是包含空列表Ints的列表.如果你跑length ([] :: [[Int]]),你会得到0,但length ([[]] :: [[Int]])你得到1!相反,只是做

plusList [] = 0
Run Code Online (Sandbox Code Playgroud)

再次,这与模式完全一样add.如果你想要plusList返回[Int],这条线应该是

plusList [] = []
Run Code Online (Sandbox Code Playgroud)

所以我们有两个版本

plusList :: [[Int]] -> Int
plusList (xs:ys) = add xs + plusList ys
plusList [] = 0
Run Code Online (Sandbox Code Playgroud)

plusList :: [[Int]] -> [Int]
plusList (xs:ys) = add xs : plusList ys
plusList [] = []
-- or just
-- plusList xs = map add xs
Run Code Online (Sandbox Code Playgroud)

但是,有一种更简单的方法可以做到这一点.首先,add它只是内置sum函数,但专门用于Ints.但是,由于内置使用,内置sum效率不高foldl.相反,您可以实现更快的变体

add :: [Int] -> [Int]
add xs = foldr (+) 0 xs
Run Code Online (Sandbox Code Playgroud)

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

此外,如果要对列表列表求和,可以使用更高阶的函数来完成

plusList = add . map add
Run Code Online (Sandbox Code Playgroud)

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