这部分代码是 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。