Last active
November 1, 2022 23:58
-
-
Save isaacabraham/0849128cc72f26779d3bbd160a97114e to your computer and use it in GitHub Desktop.
F# port of the first half of John De Goes "FP to the max" (https://www.youtube.com/watch?v=sxudIMiOo68)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#load @".paket\load\net452\FSharpPlus.fsx" | |
open FSharpPlus | |
open System | |
[<AutoOpen>] | |
module rec IO = | |
let run (IO computation) = computation() | |
type IO<'T> = | |
| IO of (unit -> 'T) | |
static member (>>=) (x, f) = IO(fun () -> run x |> f |> run) | |
static member Return (x:'T) = IO(fun () -> x) | |
[<AutoOpen>] | |
module SideEffects = | |
let private r = Random() | |
let printLn text = IO (fun () -> printfn "%s" text) | |
let readLn() = IO(fun () -> Console.ReadLine()) | |
let random upper = IO(fun () -> r.Next(0, upper)) | |
let parseInt s = Int32.TryParse s |> function | true, x -> Some x | false, _ -> None | |
let rec checkContinue name = monad { | |
do! printLn ("Do you want to continue, " + name + "?") | |
let! answer = readLn() |> map String.toLower | |
return! | |
match answer with | |
| "y" -> IO.Return true | |
| "n" -> IO.Return false | |
| _ -> checkContinue name } | |
let rec gameLoop name = monad { | |
let! secret = random 5 |> map ((+) 1) | |
do! printLn ("Dear " + name + ", please guess a number from 1 to 5:") | |
let! input = readLn() | |
do! | |
match parseInt input with | |
| None -> printLn "You did not enter a number!" | |
| Some x when x = secret -> printLn ("You guessed right, " + name + "!") | |
| Some _ -> printLn (sprintf "You guessed wrong, %s! The number was: %d" name secret) | |
let! shouldContinue = checkContinue name | |
return! | |
if shouldContinue then gameLoop name | |
else IO.Return() } | |
let main = monad { | |
do! printLn "What is your name?" | |
let! name = readLn() | |
do! printLn ("Hello, " + name + " welcome to the game!") | |
do! gameLoop name | |
return() } | |
run main |
My version here:
https://gist.github.com/giuliohome/7cabc15c38ce22d3532e8046241e0ed7
Here's my simplified version https://gist.github.com/gusty/3a9d654de320225e4a17d92049646160/revisions
Using FSharpPlus tryParse
and the async
monad.
You probably know it already, you can use async
instead of io
(that's the reason why there's no IO monad in F#+).
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I think that the port of the second part corresponds to translating Scala "capabilities" into F# "effect handlers", as they are defined in this snippet http://www.fssnip.net/7TM/title/TypeSafe-effect-builder
It is the most generic concept of a dsl.