Conway's Game of Life F# I am a C# developer learning F#. Would appreciate any suggestions on how this code can be improved. Main points I am interested in:


Functional style of the code, absense of imperative style(C#) artifacts
F# collection data types and functions usage
General code(not algorithm) efficiency
Code style, naming etc.

let life board =
    let flatten = Seq.cast&lt;int&gt; &gt;&gt; Seq.toArray

    let neighboursCount (board: int[,]) x y =
        board.[y..y+2, x..x+2]
        |&gt; flatten
        |&gt; Array.mapi (fun i el -&gt; (i &lt;&gt; 4, el))
        |&gt; Array.filter fst |&gt; Array.map snd
        |&gt; Array.filter ((=) 1) |&gt; Array.length

    let expandBoard board =
        let N = Array2D.length1 board
        array2D [|
            yield                        [| yield board.[N - 1, N - 1]; yield! board.[N - 1, *]; yield board.[N - 1, 0] |]
            for i in [0..N - 1] do yield [| yield board.[i,     N - 1]; yield! board.[i,     *]; yield board.[i,     0] |]
            yield                        [| yield board.[0,     N - 1]; yield! board.[0,     *]; yield board.[N - 1, 0] |]
        |]

    let getNextBoard board =
        let eBoard = expandBoard board
        board |&gt; Array2D.mapi (fun i j elem -&gt;
            match neighboursCount eBoard j i with
            | 2 -&gt; elem
            | 3 -&gt; 1
            | _ -&gt; 0)

    let isGameOver board prevBoards =
        board |&gt; flatten |&gt; Array.forall ((=) 0) || List.contains board prevBoards

    let rec lifeRec board prevBoards =
        printfn "%A \n" board
        if isGameOver board prevBoards
        then ()
        else getNextBoard board |&gt; lifeRec &lt;| board::prevBoards

    lifeRec board []

let N = 5
let rnd = System.Random()
Array2D.init N N (fun _ _ -&gt; rnd.Next 2) |&gt; life
This is a most elegant solution. I have two small improvements:



let neighboursCount (board: int[,]) x y =
    board.[y..y+2, x..x+2] 
    |&gt; flatten 
    |&gt; Array.indexed
    |&gt; Array.sumBy (fun (i, n) -&gt; if i &lt;&gt; 4 then n else 0)




let expandBoard board =
    let N = (Array2D.length1 board) - 1
    array2D [|
        yield                    [| yield board.[N, N]; yield! board.[N, *]; yield board.[N, 0] |]
        for i in [0..N] do yield [| yield board.[i, N]; yield! board.[i, *]; yield board.[i, 0] |]
        yield                    [| yield board.[0, N]; yield! board.[0, *]; yield board.[N, 0] |]
    |]


Here is N set to (Array2D.length1 board) - 1 because that's the value you're using through out the function.