2016-03-24 14 views
2

私はsqueen.iclのコードから試してみます。 BoardSize :== 11で試しても問題ありません。しかし、12に変更すると、出力は[になります。どうして?それを修正するには?N-Queensのサンプルプログラムの奇妙な出力

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

答えて

2

これは、ヒープ上の領域が不足しているためです。デフォルトでは、Cleanプログラムのヒープは2Mに設定されています。もちろんこれを変更することができます。コマンドラインからclmを使用する場合は、コマンドラインまたはクリーンプログラム自体のコマンドラインに-h 4Mを追加できます。クリーンIDEを使用している場合は、プロジェクトオプション、アプリケーションを使用してヒープサイズを変更できます。

(がまだ印刷されている理由は、[ではなく、次のようになります。クリーンプログラムは、出力全体がわかるまで待つのではなく、できるだけ多くの出力を出力します。例えば、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はテール再帰を利用しているため、小さなヒープでもタプルの最初の要素を計算できます(2番目の要素を[]に置き換えることでこれを試すことができます)。タプルの2番目の要素は、小さなヒープで計算することもできます(最初の要素を0に置き換えます)。

ポイントは、の前にの前に計算されます。最初に印刷する必要があるためです。通常のlengthコールの部分はガベージコレクトされますが(最初の100要素を反復処理した後、廃棄することができます)、hdコールは、リストの最初の要素がでないことを確認します。捨てられた。最初の要素が破棄されない場合、2番目の要素、3番目の要素などはどちらもできません。したがって、実際には必要ではないが、リスト全体がメモリに保持されます。 hdが呼び出された後、そこにメモリにリスト全体を維持する理由はありませんので、lengthは、それが繰り返し処理している要素を破棄することができ、

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

、およびヒープ:lengthhd呼び出しが問題を解決フリッピングいっぱいにならない。

+0

実際にありがとうございます。 –

+0

@samaこの回答では不正確になりました。厳密性アナライザが認識していないのは、単に「長さ」です'hd'より前に評価されています.2つの内容を反転すると、私は更新された答えでこれを詳しく説明します。 – Keelan