これは私の最初のF#プログラムです。最初の演習として、コンウェイのライフゲームを実装しようと思いました。
次のコードがなぜそのようなひどいパフォーマンスをするのか理解するのを手伝ってください。
let GetNeighbours (p : int, w : int, h : int) : seq<int> =
let (f1, f2, f3, f4) = (p > w, p % w <> 1, p % w <> 0, p < w * (h - 1))
[
(p - w - 1, f1 && f2);
(p - w, f1);
(p - w + 1, f1 && f3);
(p - 1, f2);
(p + 1, f3);
(p + w - 1, f4 && f2);
(p + w, f4);
(p + w + 1, f4 && f3)
]
|> List.filter (fun (s, t) -> t)
|> List.map (fun (s, t) -> s)
|> Seq.cast
let rec Evolve (B : seq<int>, S : seq<int>, CC : seq<int>, g : int) : unit =
let w = 10
let h = 10
let OutputStr = (sprintf "Generation %d: %A" g CC) // LINE_MARKER_1
printfn "%s" OutputStr
let CCN = CC |> Seq.map (fun s -> (s, GetNeighbours (s, w, h)))
let Survivors =
CCN
|> Seq.map (fun (s, t) -> (s, t |> Seq.map (fun u -> (CC |> Seq.exists (fun v -> u = v)))))
|> Seq.map (fun (s, t) -> (s, t |> Seq.filter (fun u -> u)))
|> Seq.map (fun (s, t) -> (s, Seq.length t))
|> Seq.filter (fun (s, t) -> (S |> Seq.exists (fun u -> t = u)))
|> Seq.map (fun (s, t) -> s)
let NewBorns =
CCN
|> Seq.map (fun (s, t) -> t)
|> Seq.concat
|> Seq.filter (fun s -> not (CC |> Seq.exists (fun t -> t = s)))
|> Seq.groupBy (fun s -> s)
|> Seq.map (fun (s, t) -> (s, Seq.length t))
|> Seq.filter (fun (s, t) -> B |> Seq.exists (fun u -> u = t))
|> Seq.map (fun (s, t) -> s)
let NC = Seq.append Survivors NewBorns
let SWt = new System.Threading.SpinWait ()
SWt.SpinOnce ()
if System.Console.KeyAvailable then
match (System.Console.ReadKey ()).Key with
| System.ConsoleKey.Q -> ()
| _ -> Evolve (B, S, NC, (g + 1))
else
Evolve (B, S, NC, (g + 1))
let B = [3]
let S = [2; 3]
let IC = [4; 13; 14]
let g = 0
Evolve (B, S, IC, g)
最初の5回の反復、つまり世代0、1、2、3、4は、問題なく発生します。次に、約100ミリ秒の短い休止の後、第5世代が完了します。ただし、その後、ブレークポイントVisual Studioで示されるように、プログラムは「LINE_MARKER_1」とマークされた行でハングします。printfn
それは決してラインに到達しません。
奇妙なことに、すでに第2世代までCC
に、関数内のシーケンスEvolve
はすでにシーケンスに安定している[4; 13; 14; 3]
ため、第6世代が進化しない理由はわかりません。
コードの大きなセグメントを貼り付けてデバッグの助けを求めることは一般的に不適切であると考えられていることを理解していますが、これを最小限の実用的な例に減らす方法がわかりません。デバッグに役立つポインタはありがたいことに感謝します。
よろしくお願いします。
編集
私を助けたいと思っている人は、その機能をほとんど無視するかもしれないと本当に信じていGetNeighbours
ます。完全を期すためだけに含めました。