简体   繁体   English

N-Queens 示例程序奇怪的输出

[英]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 solutionshd 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:翻转lengthhd调用解决了这个问题:

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.

相关问题 Haskell中的N-queens没有列表遍历 - N-queens in Haskell without list traversal Haskell中的8个皇后区未知错误 - 8 queens unknown error in haskell 函数式语言中的 Kernighan & Ritchie 字数统计示例程序 - Kernighan & Ritchie word count example program in a functional language 如何创建一个 function 接受 N 个数字并生成一个包含这些元素编号的列表列表,如示例中所示? - How to create a function that takes N numbers and produces a list of lists with those element numbers, as in the example? 例外:Prelude.last:Haskell解决8皇后的空列表? - Exception: Prelude.last: empty list in Haskell solving 8-queens? 如何从Haskell程序输出PostScript文件? - How can one output a PostScript file from a Haskell program? Clojure:使用输出作为下一个操作的输入执行n次操作(a-la reduce) - Clojure: Executing an operation n times using the output as input of next operation (a-la reduce) 创建一个具有输入n和输入_函数的new_function,它们返回一个input_function进行n次input_function的操作 - Create a new_function which has an input n and input_function which return a output_function that does what input_function does n times 有什么好的例子:“程序的操作应该将输入值映射到输出值而不是更改数据” - What are good examples of: “operation of a program should map input values to output values rather than change data in place” 奇怪的flatMap返回类型 - strange flatMap return type
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM