Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functional Refactor #3

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open

Conversation

jbtule
Copy link

@jbtule jbtule commented Sep 16, 2020

  • Zero mutations in nextGeneration
  • Change print to pure function stringily
  • Moved all side effects and mutations to main function
  • Changed while loop with static bool to async with cancelation token
  • Reduced LOC further
  • No longer ignores outer edge

Copy link
Author

@jbtule jbtule left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments on choices and showcasing F# syntax.


type Status = ``💀`` = 0 | ``😁`` = 1
type RNG = Security.Cryptography.RandomNumberGenerator
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Want a single type, but not bulky name? Use a type alias!

let aliveNeighbors =
(seq { -1 .. 1 }, seq { -1 .. 1 })
||> Seq.allPairs
|> Seq.choose (function | (0, 0) -> None | x -> Some x) //skip center
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

function | is a special lambda of match cases.

Thread.Sleep(timeout)
let private stringify (grid: Status [,]) =
grid
|> Array2D.mapi (fun _ y -> if y = columns - 1 then sprintf "%A\n" else string)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curried form functions means multiple arguments can be invoke like nested single argument functions and vice versa. Many might not be a fan of this, but I like, the if expression returns a choice of functions from inside a two argument function to make a three argument function!

Comment on lines +41 to +51
let work = async {
// randomly initialize our grid
let mutable grid =
Array2D.init rows columns (fun _ _ -> RNG.GetInt32(0, 2) |> enum)
while true do
// Displaying the grid
Console.SetCursorPosition(0, 0)
grid |> stringify |> Console.Write
grid <- nextGeneration grid
do! Async.Sleep timer
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

async, unlike task, doesn't start where you declare it (cold rather than hot). Makes it easier to structure and compose.

runSimulation <- false
Console.WriteLine("\n👋 Ending simulation."))
let cts = new CancellationTokenSource()
Console.CancelKeyPress.Add(fun _ -> cts.Cancel(); Console.WriteLine "\n👋 Ending simulation.")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

F# doesn't need semicolons, but you can swap with a new line for most things.

|> Array2D.mapi (fun r c ->
let aliveNeighbors =
(seq { -1 .. 1 }, seq { -1 .. 1 })
||> Seq.allPairs
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

||> will pipe tuple items into two arguments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant