这是我的第一个F#计划.我以为我会把Conway的生命游戏作为第一个练习. 请帮助我理解为什么下面的代码有如此可怕的性能. let GetNeighbours (p : int, w : int, h : int) : seqint = let (f1, f2, f3, f4) =
请帮助我理解为什么下面的代码有如此可怕的性能.
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)
前五次迭代,即第0代,第1代,第2代,第3代,4代,没有问题.然后,在大约100毫秒的短暂停顿之后,完成第5代.但在那之后,程序挂起标记为“LINE_MARKER_1”的行,正如断点Visual Studio所揭示的那样.它永远不会到达printfn线.
奇怪的是,已经是第2代,函数Evolve中的CC序列已经稳定到序列[4; 13; 14; 3]所以我认为没有理由为什么第6代不能进化.
我知道通常认为粘贴大段代码并在调试时请求帮助是不合适的,但我不知道如何将其减少到最小的工作示例.我们将非常感谢任何有助于我调试的指针.
在此先感谢您的帮助.
编辑
我真的相信任何希望帮助我的人都可能会忽略GetNeighbours功能.我把它包括在内是为了完整起见.
看到评论和所有,但这个代码运行像地狱 – 使用List.*和一些其他较小的优化:let GetNeighbours p w h = 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.choose (fun (s, t) -> if t then Some s else None) let rec Evolve B S CC g = let w = 10 let h = 10 let OutputStr = sprintf "Generation %d: %A" g CC // LINE_MARKER_1 printfn "%s" OutputStr let CCN = CC |> List.map (fun s -> s, GetNeighbours s w h) let Survivors = CCN |> List.choose (fun (s, t) -> let t = t |> List.filter (fun u -> CC |> List.exists ((=) u)) |> List.length if S |> List.exists ((=) t) then Some s else None) let NewBorns = CCN |> List.collect snd |> List.filter (not << fun s -> CC |> List.exists ((=) s)) |> Seq.countBy id |> List.ofSeq |> List.choose (fun (s, t) -> if B |> List.exists ((=) t) then Some s else None) let NC = List.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