haskell中的递归函数?

时间:2013-02-07 09:18:39

标签: haskell recursion

我正在尝试学习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.我想我必须首先做一个函数保护然后总结它,但我不知道如何用递归行为来做。

2 个答案:

答案 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)]

这看起来更贴近你给出的例子。它以1test 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。