2017-03-28 30 views
1

我必须通过尾递归获取卡片列表中Card的数量。我得到了下面的代码:Haskell在列表尾递归中计数元素

amountCard :: Int -> Card -> [Card] -> Int 

我试图至今:

amountCard n c [] = n 
amountCard n k (x:xs) = if k == x then amountCard (n+1) k xs else amountCard n k xs 

难道我用尾递归在这里?

+0

你最好使用*警卫*而不是'if-then-else'。 –

回答

4

那么这Wikipedia article说:

[A]尾呼叫是作为一个程序的最后行动 进行子程序调用。如果尾部呼叫可能导致相同子程序 在呼叫链中稍后被再次呼叫,则该子程序被称为 是尾递归,这是递归的特例。尾递归(或尾递归)特别有用,并且在实现中通常易于处理。

(格式化后加)

现在,如果你使用if - then - 后else并没有什么,你知道thenelse条款的身体将是最后东西“程序”将做。由于在这些thenelse条款的身体是简单电话(有没有“后处理”1 + (amountCard n k xs)),这的确是尾递归。

我不过说,这是更优雅的使用警卫if - then - else结构:

amountCard n c [] = n 
amountCard n k (x:xs) | k == x = amountCard (n+1) k xs 
         | otherwise = amountCard n k xs
在Haskell

而且如果一个变量是通常通配符模式使用不重视,如:

amountCard n _ [] = n 
amountCard n k (x:xs) | k == x = amountCard (n+1) k xs 
         | otherwise = amountCard n k xs

而且作为被@chepner注意,您可以通过电子邮件asily你的代码转换为:

amountCard n c [] = n 
amountCard n k (x:xs) = amountCard (if k == x then n + 1 else n) k xs

而现在它显然是尾递归,因为第二条的机身仅包含一个调用相同的功能(使用不同的参数)。

+2

请注意,由于'if-then-else'是一个表达式,因此您可以使用它来指定正确的参数而不使用警卫:'amountCard nk(x:xs)= amountCard(if k == x then n + 1 else n)k xs'。 – chepner

+0

@chepner:这确实是一个很好的论点。我用你的节点更新了答案。谢谢。 –