Skip to content

Instantly share code, notes, and snippets.

@OnurGumus
Last active May 25, 2019 09:43
Show Gist options
  • Save OnurGumus/d97da98ae9b83d17e875d6e298c81db5 to your computer and use it in GitHub Desktop.
Save OnurGumus/d97da98ae9b83d17e875d6e298c81db5 to your computer and use it in GitHub Desktop.
open System
#if FABLE_COMPILER
open Fable.Core
open Fable
[<Emit("prompt($0,'')")>]
let prompt (s1 : string ) : string = jsNative
#else
let prompt (s1 : string) : string =
printfn "%s" s1
Console.ReadLine()
#endif
module Async =
let map f workflow = async { let! res = workflow
return f res }
let bind f workflow = async.Bind(workflow, f)
type ResultOrStop<'u,'v> = Stop | Result of Result<'u,'v>
with
static member map f workflow : ResultOrStop<'u,'v> =
match workflow with
| Stop -> Stop
| Result(Error z) -> Result(Result.Error z)
| Result (Ok k) -> k |> f |> Ok |> Result
type FMap = FMap with
static member($) (FMap, x:Async<_>) = fun f-> Async.map f x
static member($) (FMap, x:Result<_,_>) = fun f -> Result.map f x
static member($) (FMap, x:ResultOrStop<_,_>) = fun f -> ResultOrStop.map f x
let inline fmap f x = FMap $ x <| f
type Return = Return with
static member ($) (Return, t:'a option) = fun (x:'a) -> Some x
let inline return' x : ^R = (Return $ Unchecked.defaultof< ^R> ) x
type Bind = Bind with
static member ($) (Bind, x:Async<_>) = fun f -> Async.bind f x
let inline (>>=) x f = Bind $ x <| f
let inline bind f x = Bind $ x <| f
let inline dmap k = k |> fmap |> fmap
let readInput() = async { return prompt ("Enter a number:") }
let random() = async { return System.Random().Next(100) }
let write (out : string) = async { return Console.WriteLine(out) }
type ComparisonResult =
| Equal of int
| Great of int
| Small of int
let parseInput (s : string) =
Int32.TryParse s |> function
| false, _ when s = "stop" -> Stop
| false, _ -> (Result.Error s) |> Result
| true, i -> (Result.Ok i) |> Result
let test (target : int) (input : int) =
if input > target then Great input
else if input < target then Small input
else Equal input
let (|GreaterThan|_|) smallerNumber n =
if n > smallerNumber then Some n
else None
let (|DivisibleBy|_|) dividedBy n =
if n % dividedBy = 0 then Some n
else None
let testSmaller =
function
| Great(DivisibleBy 5 n) -> Small n
| other -> other
let testDivisibleBy =
function
| Small(GreaterThan 50 n) & Small (DivisibleBy 7 _) -> Great n
| other -> other
type ContOrStop =
| Continue
| Stop
let handle comparison =
async {
match comparison with
| ResultOrStop.Stop -> return Stop
| Result(Error _) ->
do! write "Re enter the number"
return Continue
| Result(Ok(Equal _)) ->
do! write "bingo!"
return Stop
| Result(Ok(Great _)) ->
do! write "Greater"
return Continue
| Result(Ok(Small _)) ->
do! write "Smaller"
return Continue
}
let rec turn r =
readInput
>> fmap parseInput
>> dmap (test r)
>> dmap testSmaller
>> dmap testDivisibleBy
>> bind handle
>> bind (function
| Continue -> turn r
| Stop -> async.Return())
<| ()
let program = random >> bind turn
program () |> Async.StartImmediate
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment