【问题标题】:N-Queens example program strange outputN-Queens 示例程序奇怪的输出
【发布时间】:2016-03-24 03:42:48
【问题描述】:

我尝试了squeen.icl 示例中的代码。当我用BoardSize :== 11 尝试时,没有问题。但是当我将其更改为12 时,输出为[。为什么?如何解决?

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 [] []

【问题讨论】:

    标签: functional-programming n-queens clean-language


    【解决方案1】:

    这是因为堆上的空间不足。默认情况下,清理程序的堆设置为 2M。当然,您可以更改此设置。从命令行使用clm 时,您可以将-h 4M 添加到其命令行或clean 程序本身的命令行。如果您使用的是 Clean IDE,则可以通过 Project Options、Application 更改堆大小。

    ( 仍然被打印的原因(这是我得到的,而不是[),原因如下。 Clean 程序将尽可能多地输出其输出,而不是等到知道整个输出为止。这意味着,例如,Start = [0..] 这样的简单行将向您的终端发送垃圾邮件,而不是等到整个无限列表都在内存中然后打印它。在squeen.icl 的情况下,Clean 看到 Start 的结果将是一个元组,因此直接打印左大括号。但是,当尝试计算元组的元素(length solutionshd solutions)时,堆会填满,导致程序终止。

    我不知道当你在 Windows 上获得一个完整的堆时会是什么样子,但在 Linux(/Mac) 上,它看起来像这样:

    $ clm squeen -o squeen && ./squeen -h 2M
    Linking squeen
    Heap full.
    Execution: 0.13  Garbage collection: 0.03  Total: 0.16
    ($
    

    注意元组左大括号在最后一行。因此,使用终端时很容易发现此错误。

    有趣的是,由于length 利用尾递归,因此可以计算元组的第一个元素,即使堆很小(您可以尝试用[] 替换第二个元素)。元组的第二个元素也可以在一个小堆上计算(将第一个元素替换为0)。

    关键是长度是在头部之前计算的,因为它必须首先打印。虽然使用普通的length 调用,列表的一部分被垃圾收集(在迭代前 100 个元素之后,它们可以被丢弃,从而允许更小的堆使用),hd 调用确保列表的第一个元素被丢弃。如果第一个元素没有被丢弃,那么第二个元素和第三个元素都不会被丢弃,等等。因此,整个列表都保存在内存中,而这实际上并不是必需的。翻转lengthhd 调用即可解决问题:

    Start :: ([Int], Int)
    Start = (hd solutions, length solutions)
    where solutions = Queens 1 [] []
    

    现在,在调用hd 之后,没有理由将整个列表保存在内存中,因此length 可以丢弃它迭代过的元素,并且堆不会填满。

    【讨论】:

    • 其实是'('。谢谢。
    • @sama 我发现这个答案不准确。并不是严格分析器不识别,只是lengthhd 之前被评估。翻转两者可以解决此问题。我在更新的答案中对此进行了详细说明。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-16
    • 1970-01-01
    • 1970-01-01
    • 2021-07-13
    • 2014-02-04
    • 2020-05-14
    相关资源
    最近更新 更多