2013-12-08 51 views
0

特定Int的号码,我想创建一个功能countElems接受一个Int[Int]和回报多少的特定Int是在列表中。到目前为止,我有:在Haskell如何计算列表中

countElems :: Int -> [Int] -> Int 
countElems n (x:xs) 
| xs == [] = 0 
| n == x  = 1 + countElems n xs 
| n /= x  = countElems n xs 

运行时,这似乎是工作,但进一步的检查,如果输入countElems 9 [5, 3, 9, 3, 9]输出为1,而不是2。我可以看到这是因为在看到n == x导致错误输出之前检查xs == [],但是如果我将这两种情况交换为Non-exhaustive pattern。进一步的思考后

编辑:

我可以消除错误@ user2407038贴有这样的代码:

countElems :: Int -> [Int] -> Int 
countElems _ [] = 0 
countElems n (x:xs) 
| n == x  = 1 + countElems n xs 
| n /= x  = countElems n xs 

这看起来不太优雅,但工作得一样吗?

回答

2

你的功能是不可穷尽的,无论哪个命令你把卫兵考虑countElems 9 []。这是一个错误,因为没有模式匹配空列表。 (也许这是你的情况所需的行为 - 但通常错误是不好的)。这里考虑使用模式匹配:

countElems n (x:xs) = fromEnum (n == x) + countElems n xs 
countElems _ []  = 0 

fromEnum避免if我喜欢,但你不必使用它。

这里可能没有必要使用显式递归。尝试\x = length . filter (==x)

+0

我喜欢这个答案,因为它让我的讲师错了,他说我们需要两个递归的例子,但这是解决这个问题的一个非常好的方法,谢谢! – benharris

+5

@benharris讲师常常是“错误的”,因为他们教给你的东西并不一定是一个熟练的程序员会写的东西。真实世界的Haskell代码根本没有非常多的递归。它的大部分功能都可以通过库函数来实现,这使得代码更具可读性,更易于维护,减少了容易出错的情况等等。 – kqr

2

在你第一次检查(xs == [] = 0)你忘了检查是否x==n在这种情况下,结果应该是1代替0

countElems n (x:xs) 
| xs == [] = if x==n then 1 else 0 
| n == x  = 1 + countElems n xs 
| n /= x  = countElems n xs 

另一个(可能更简单)的实现可能看列表作为整体:

cE n [] = 0 
cE n (x:xs) = (if n==x then 1 else 0) + (cE n xs) 
+0

谢谢,第一个解决方案是伟大的。我非常有兴趣知道第二种解决方案在做什么,但我不认为我在Haskell的那个级别,但是'cE'在做什么? – benharris

+0

@benharris名称'cE'只是用于'countElems'的简写形式。它总是“看起来”第一个元素,并且只在第一个元素是你正在寻找的元素时才添加一个元素。 – phimuemue

0

您还可以使用地图写:

countElems :: Int -> [Int] -> Int 
countElems n xs = sum $ map (fromEnum . (==n)) xs 
5

而另一个没有任何递归条款:

countElem e = length . filter (e ==)