我正在尝试学习Haskell并正在研究递归函数的书籍问题。
> If X_1 = 1 then X_2 = 1 + X_1 = 2, X_3 = 1 + X_1 + X_2
or when it is 5, X_5 = 1 + X_4 + X_3 + X_2 + X_1 = 16, and so forth.
我尝试在haskell上执行此操作:
test :: Int -> Int
test 1 = 1
test n = sum[test n .. test (n-1)]
但是输出总是1.我想我必须首先做一个函数保护然后总结它,但我不知道如何用递归行为来做。
答案 0 :(得分:5)
一个好的起点是列表推导:
[ test i | i <- [1..5] ]
装置
[ test 1, test 2, test 3, test 4, test 5 ]
看看你现在能否解决它。
不要忘记添加1!
答案 1 :(得分:3)
这部分代码是Haskell范围
[test n .. test (n-1)]
范围通过计算左边的数字和正确的数字来工作,然后构建一个包含从左边数字到右边数字的所有步骤的列表。所以:
[1 .. 6] --> [1,2,3,4,5,6]
[5 .. 9] --> [5,6,7,8,9]
正如您所看到的,默认步骤为1,因此如果您的左侧数字高于右侧,您将获得一个空列表:
[4 .. 3] --> []
另外,您可以通过提供另一个数字来覆盖默认步骤:
[1, 3 .. 6] --> [1,3,5] -- step is 2
[8, 6 .. 3] --> [8,6,4] -- step is -2
正如您所看到的,当您有另一个步长大于1时,您必须小心结果列表中包含的内容。这尤其适用于否定步骤,如果您使用非整数步骤(例如[1, 1.25, .. 2.1]
),则会更多。您几乎不应该使用范围生成非整数数列表。
在您的解决方案中,您有一行
test n = sum[test n .. test (n-1)]
根据范围规则,这肯定会出错。当程序尝试从范围中生成列表时,它会尝试计算test n
,因为这是范围的左数。但是这让我们无处可去,因为test n
是整个线路首先想要计算的东西。所以我们有一个无限循环,程序挂起。
您可以尝试
test n = sum[1 .. test (n-1)]
这看起来更贴近你给出的例子。它以1
(test 1
)开头,以test (n-1)
结尾。但问题在于它们之间的那些价值。因为范围是一步,所以你最终得到的是:
[1 .. test (n-1)] --> [1,2,3, ......., test (n-1)]
与
不一样[test 1, test 2, test 3, .... , test (n-1)]
由于范围只能有一个恒定的步长,因此即使您覆盖默认步骤,也无法使用简单范围获得最后一行。关于如何解决这个问题的一个提示是注意列表中的元素数量。
length [1 .. test (n-1)] --> test (n-1),
-- because [1,2,3] has 3 elements, [1,2,3,4] has 4 and so on
length [test 1, test 2, test 3, ....... , test (n-1)] --> n-1
-- this is not quite Haskell syntax
这里的Haskell方法是创建一个具有正确数量的元素的列表,然后对其进行转换,使每个元素都是正确的元素。你如何列出(n-1)
元素?简单:
[1..(n-1)]
从这里你可以走几条路。 luqui有列表理解:
[test x | x <- [1..(n-1)]]
您可以将此视为将每个数字排除在范围之外,将其分配给x
,然后将test
功能应用于x
,以便获得[test 1, test 2, test 3, ....... , test (n-1)]
。另一种方法是使用map
函数:
map test [1..(n-1)]
我认为这是同时将test
应用于列表的每个元素,但它与列表理解完全相同,只是两种方式来查看它。请注意,两种方式都使用[1..(n-1)]
范围。
如果您在原始代码中使用其中任何一个而不是[test n .. test (n-1)]
范围,那么您就非常接近解决方案。正如luqui提醒的那样,唯一缺少的是记住添加1。