0

我正在尝试学习 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。我想我必须先做一个函数保护然后对其求和,但我不知道如何用递归行为来做到这一点。

4

2 回答 2

5

一个好的起点是列表推导:

[ test i | i <- [1..5] ]

方法

[ test 1, test 2, test 3, test 4, test 5 ]

看看你现在能不能解决。

别忘了加1!

于 2013-02-07T09:26:20.227 回答
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。

于 2013-02-07T14:09:36.153 回答