我已经清楚原始递归定义是什么,但是我似乎仍然无法理解它。
例如,我似乎无法向自己解释如何执行以下操作(但我似乎能够这样做):
练习:
定义功能
productIt :: [Int] -> Int
它给出了整数列表的乘积,并为空列表返回1;为什么选择这个特定值作为空列表的结果?
我(当然)提出了解决方案:
productIt :: [Int] -> Int
productIt [] = 1
productIt (x:xs) = x * productIt xs
完美适用于练习中的问题。然而,我似乎仍然难以绕过最后一行。
关于如何考虑这一点的任何想法都将受到最高的赞赏。
答案 0 :(得分:5)
在英语中,您可以将最后一行读作:
数字列表的乘积是第一个数字乘以其余数字的乘积。如果没有数字,我们只说产品是1。
将它转换为英语通常可以帮助我理解递归函数的工作原理和原因。您也可以使用头脑中的Haskell解释器来评估它:
productIt [2,3,4]
= 2 * (productIt [3,4])
= 2 * (3 * (productIt [4]))
= 2 * (3 * (4 * (productIt [])))
= 2 * (3 * (4 * (1)))
= 2 * (3 * (4))
= 2 * (12)
= 24
答案 1 :(得分:2)
你使用1作为普通案例[]的原因是因为当你乘以它时它不会改变结果。
productIt (x:xs) = x * productIt xs
例如,假设您将其定义为:
productIt [] = 2 -- line 1
productIt (x:xs) = x * productIt xs -- line 2
然后考虑:
productIt [1] = productIt (1:[])
= 1 * productIt [] -- by line 2
= 1 * 2 -- by line 1
= 2 -- WRONG!!!
您正在寻找整数列表的乘积,对于[1],答案应该是1.
答案 2 :(得分:1)
在我解释最后一行代码之前,让我总结一下解决此类问题的过程。有两个关键问题:
好的,所以我们想写一个函数来计算列表中所有数字的乘积。
问题1:最简单的情况是没有任何数字。如果这是我第一次遇到这个问题,对我来说可能不是很明显,在这种情况下答案应该是什么,但让我们暂时把它放在一边。
问题2:如果我有一个列表[n0,n1,n2,.. nk],并且我知道除了第一个之外的所有数字的产品(我们称之为p),那么答案就是第一个元素乘以该产品,或n0 * p。
第一行代码将处理琐碎的案例:
productIt [] = 1
这就是说空列表参数[]的函数productIt的值为1.(我在上面解释了为什么答案必须是1.)这样可以解决这个小问题。现在我们需要在列表不为空的情况下定义productIt。让我们看看最后一行代码:
productIt (x:xs) = ... something?
左侧使用模式匹配。模式(x:xs)将匹配具有一个或多个元素的列表。当该表达式匹配时,它将x绑定到第一个元素,将xs绑定到列表的其余部分。因此,我们不仅匹配模式,我们将x和xs定义为奖励。这就是使模式匹配在Haskell中非常强大的原因。
因此,如果列表的第一个元素是x,列表的其余部分(除第一个元素之外的所有元素)都是xs,那么答案是什么?我们已经确定它是所有剩余元素(xs)的乘积的第一个元素(x)。所以......
productIt (x:xs) = x * productIt xs
另外,yjerem给出了一个关于Haskell如何评估它的出色解释。