[英]N-Queens example program strange output
I try the code from the squeen.icl
example.我尝试使用
squeen.icl
示例中的代码。 When I try it with BoardSize :== 11
, there is no problem.当我尝试使用
BoardSize :== 11
,没有问题。 But when I change it to 12
, the output is [
.但是当我将其更改为
12
,输出为[
。 Why?为什么? How to fix that?
如何解决?
module squeen
import StdEnv
BoardSize :== 12
Queens::Int [Int] [[Int]] -> [[Int]]
Queens row board boards
| row>BoardSize = [board : boards]
| otherwise = TryCols BoardSize row board boards
TryCols::Int Int [Int] [[Int]] -> [[Int]]
TryCols 0 row board boards = boards
TryCols col row board boards
| Save col 1 board = TryCols (col-1) row board queens
| otherwise = TryCols (col-1) row board boards
where queens = Queens (row+1) [col : board] boards
Save::!Int !Int [Int] -> Bool
Save c1 rdiff [] = True
Save c1 rdiff [c2:cols]
| cdiff==0 || cdiff==rdiff || cdiff==0-rdiff = False
| otherwise = Save c1 (rdiff+1) cols
where cdiff = c1 - c2
Start::(Int,[Int])
Start = (length solutions, hd solutions)
where solutions = Queens 1 [] []
This is because you're running out of space on the heap.这是因为堆上的空间不足。 By default, the heap of Clean programs is set to 2M.
默认情况下,Clean 程序的堆设置为 2M。 You can change this, of course.
当然,您可以更改此设置。 When using
clm
from the command line, you can add -h 4M
to its command line or to the command line of the clean program itself.从命令行使用
clm
,您可以将-h 4M
添加到其命令行或 clean 程序本身的命令行。 If you're using the Clean IDE, you can change the heap size through Project Options, Application.如果您使用的是 Clean IDE,则可以通过“项目选项”、“应用程序”更改堆大小。
The reason that (
is still printed (which is what I get, rather than [
), is the following. A Clean program will output as much of its output as possible, rather than waiting until the whole output is known. This means, for example, that a simple line as Start = [0..]
will spam your terminal, not wait until the whole infinite list is in memory and then print it. In the case of squeen.icl
, Clean sees that the result of Start will be a tuple, and therefore prints the opening brace directly. However, when trying to compute the elements of the tuple ( length solutions
and hd solutions
), the heap fills up, making the program terminate. (
仍然打印(这是我得到的,而不是[
) 的原因如下。一个 Clean 程序将输出尽可能多的输出,而不是等到整个输出已知。这意味着,对于例如,像Start = [0..]
这样的简单行会向您的终端发送垃圾邮件,而不是等到整个无限列表都在内存中后再打印它。在squeen.icl
的情况下,Clean 看到 Start 的结果将是一个元组,因此直接打印左括号。但是,当尝试计算元组的元素( length solutions
和hd solutions
)时,堆填满,使程序终止。
I don't know what it looks like when you get a full heap on Windows, but on Linux(/Mac), it looks like this:我不知道当你在 Windows 上得到一个完整的堆时会是什么样子,但在 Linux(/Mac) 上,它看起来像这样:
$ clm squeen -o squeen && ./squeen -h 2M
Linking squeen
Heap full.
Execution: 0.13 Garbage collection: 0.03 Total: 0.16
($
Note that the tuple opening brace is on the last line.请注意,元组大括号在最后一行。 So, when using a terminal it is quite easy to spot this error.
因此,在使用终端时很容易发现此错误。
Interestingly, since length
exploits tail recursion, the first element of the tuple can be computed, even with a small heap (you can try this by replacing the second element with []
).有趣的是,由于
length
利用了尾递归,因此即使使用小堆也可以计算元组的第一个元素(您可以通过将第二个元素替换为[]
来尝试此操作)。 Also the second element of the tuple can be computed on a small heap (replace the first element with 0
).元组的第二个元素也可以在一个小堆上计算(用
0
替换第一个元素)。
The point is that the length is computed before the head, since it has to be printed the first.关键是长度在头部之前计算,因为它必须首先打印。 While with a normal
length
call parts of the list are garbage collected (after iterating over the first 100 elements, they can be discarded, allowing for smaller heap usage), the hd
call makes sure that the first element of the list is not discarded.虽然使用正常
length
调用列表的部分是垃圾收集(在迭代前 100 个元素后,它们可以被丢弃,允许使用较小的堆),但hd
调用确保列表的第一个元素不会被丢弃。 If the first element is not discarded, than neither can the second be, the third, etc. Hence, the whole list is kept in memory, while this is not actually necessary.如果第一个元素没有被丢弃,那么第二个元素、第三个元素等都不会被丢弃。因此,整个列表都保存在内存中,而这实际上并不是必需的。 Flipping the
length
and hd
calls solve the issue:翻转
length
和hd
调用解决了这个问题:
Start :: ([Int], Int)
Start = (hd solutions, length solutions)
where solutions = Queens 1 [] []
Now, after hd
has been called, there is no reason to keep the whole list in memory, so length
can discard elements it has iterated over, and the heap doesn't fill up.现在,在调用
hd
之后,没有理由将整个列表保留在内存中,因此length
可以丢弃它迭代过的元素,并且堆不会填满。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.