2

例のコードを試します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 [] []
4

1 に答える 1

2

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

まだ印刷されている理由((これは私が得るものではなく[)は次のとおりです。Clean プログラムは、出力全体がわかるまで待つのではなく、できるだけ多くの出力を出力します。これは、たとえば、Start = [0..]無限リスト全体がメモリに格納されるまで待機せずに、as という単純な行が端末にスパムを送信することを意味します。の場合squeen.icl、Clean は Start の結果がタプルになることを認識し、開き括弧を直接出力します。ただし、タプル ( length solutionsand 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末尾再帰を利用するため、小さなヒープでもタプルの最初の要素を計算できます (2 番目の要素を に置き換えることでこれを試すことができます[])。また、タプルの 2 番目の要素は小さなヒープで計算できます (最初の要素を に置き換えます0)。

ポイントは、最初に印刷する必要があるため、長さはヘッドのに計算されることです。通常のlength呼び出しでは、リストの一部がガベージ コレクションされますが (最初の 100 個の要素を反復処理した後、それらを破棄できるため、ヒープの使用量を減らすことができます)、hd呼び出しでは、リストの最初の要素が破棄されないようにします。最初の要素が破棄されない場合、2 番目、3 番目なども破棄されません。したがって、リスト全体がメモリに保持されますが、これは実際には必要ありません。と の呼び出しを反転するlengthと、問題が解決します。hd

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

が呼び出された後、hdリスト全体をメモリに保持する理由がないため、length繰り返し処理された要素を破棄でき、ヒープがいっぱいになりません。

于 2016-03-24T06:44:18.160 に答える