haskell中的Sum函数产生'非详尽模式'错误

时间:2013-09-28 19:30:00

标签: haskell

以下是产生错误的代码示例:

amount :: [Int, Int, Int] -> Int
amount [(a, b, c)] = sum( map getBalance [(a, b, c)])
                         where getBalance :: (Int,Int,Int) -> Int
                               getBalance (d, e, f) = f
amount [] = 0

最初代码只是:

amount :: [Int, Int, Int] -> Int
amount [(a, b, c)] = sum [c]

但是我尝试重写和添加内容以查看是否可以找到错误的原因,而我无法做到。我对Haskell很陌生,所以如果这是一个愚蠢的错误,我会支持。

4 个答案:

答案 0 :(得分:4)

您编写的类型签名描述了三个Ints的列表:[Int, Int, Int]。然而,列表类型具有不确定的长度,并且您编写的金额函数似乎期望3个元组的Ints,其将被写为[(Int, Int, Int)];无论如何,这可以从定义中得出。因此将第一个代码块加载到ghci中:

test.hs:1:11:
    Illegal type: '[Int, Int, Int]

一旦我提供了更长的输入列表,就会出现第二个错误:

*Main> amount [(1,2,3),(4,5,6)]
*** Exception: test.hs:(2,1)-(5,13): Non-exhaustive patterns in function amount

这里的问题是两个模式都不匹配:你有一个或零个条目的列表模式,但不是更多。看到[(a, b, c)]是一个重复的表达式,我们如何才能替换它?

amount [] = 0
amount xs = sum( map getBalance xs)
                     where getBalance :: (Int,Int,Int) -> Int
                           getBalance (d, e, f) = f

现在任何长度的列表都会传递给map,这很好,因为它意味着处理任意长度。实际上sum也是如此,所以我们甚至不需要为空列表添加特殊情况。

如果您要为长于一个的列表添加模式,则传统表单为x:xs,将其分为头x和尾xs。该模式与空列表不匹配,因为它无法拆分。

原始代码的问题还在于它只定义了一个元组列表的版本。我们可以使用列表推导或映射来处理:

amount1 abcs = sum [c | (a,b,c) <- abcs]
amount2 = sum . map (\(a,b,c) -> c)

所有这些变体做同样的事情,即使amount2甚至没有提到一个论点。

答案 1 :(得分:1)

首先,你的类型签名是错误的,它必须是

amount :: [(Int, Int, Int)] -> Int

出现“非穷尽模式错误,因为您只提供了两种列表: 在底部是空列表[]的情况,在上面的情况下,列表包含一个元素 ([(a,b,c)]是一个包含元素(a,b,c)的列表。因此,您的代码可以使用amount [(1,2,3)]

最简单的方法:将[(a,b,c)]替换为xs,位于=和右侧的左侧。

答案 2 :(得分:0)

(a,b,c)是一个元组:(a,b,c) = (,,) a b c

amount :: [(Int, Int, Int)] -> Int
amount [(a, b, c)] = ...

正确的

答案 3 :(得分:0)

我当然不建议在“严肃”代码中使Int成为Monoid,但工作:

import qualified Data.Foldable as F
import Data.Monoid

amount :: [(Int,Int,Int)] -> Int
amount xs = let (_,_,x) = F.fold xs in x 

instance Monoid Int where
  mempty = 0
  mappend = (+)