[英]N-Queens example program strange output
我嘗試使用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 [] []
這是因為堆上的空間不足。 默認情況下,Clean 程序的堆設置為 2M。 當然,您可以更改此設置。 從命令行使用clm
,您可以將-h 4M
添加到其命令行或 clean 程序本身的命令行。 如果您使用的是 Clean IDE,則可以通過“項目選項”、“應用程序”更改堆大小。
(
仍然打印(這是我得到的,而不是[
) 的原因如下。一個 Clean 程序將輸出盡可能多的輸出,而不是等到整個輸出已知。這意味着,對於例如,像Start = [0..]
這樣的簡單行會向您的終端發送垃圾郵件,而不是等到整個無限列表都在內存中后再打印它。在squeen.icl
的情況下,Clean 看到 Start 的結果將是一個元組,因此直接打印左括號。但是,當嘗試計算元組的元素( length solutions
和hd 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
調用確保列表的第一個元素不會被丟棄。 如果第一個元素沒有被丟棄,那么第二個元素、第三個元素等都不會被丟棄。因此,整個列表都保存在內存中,而這實際上並不是必需的。 翻轉length
和hd
調用解決了這個問題:
Start :: ([Int], Int)
Start = (hd solutions, length solutions)
where solutions = Queens 1 [] []
現在,在調用hd
之后,沒有理由將整個列表保留在內存中,因此length
可以丟棄它迭代過的元素,並且堆不會填滿。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.