Skip to content

Instantly share code, notes, and snippets.

@OnurGumus
Created January 24, 2017 15:56
Show Gist options
  • Save OnurGumus/797b99e51233f3911caa7a1cdff4ee72 to your computer and use it in GitHub Desktop.
Save OnurGumus/797b99e51233f3911caa7a1cdff4ee72 to your computer and use it in GitHub Desktop.
FSharp type classes
// Learn more about F# at http://fsharp.org
// See the 'F# Tutorial' project for more help.
open System
module Async =
let map f workflow = async { let! res = workflow
return f res }
let bind f workflow = async.Bind(workflow, f)
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
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 Console.ReadLine() }
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 =
Int32.TryParse s |> function
| false, _ -> Result.Error s
| true, i -> Result.Ok i
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) -> Great n
| other -> other
let asyncResultMap k =
k
|> Result.map
|> Async.map
type ContOrStop =
| Continue
let handle comparison =
async {
match comparison with
| Error _ ->
do! write "Re enter the number"
return Continue
| Ok(Equal _) ->
do! write "bingo!"
return Stop
| Ok(Great _) ->
do! write "Greater"
return Continue
| 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())
<| ()
[<EntryPoint>]
let main argv =
bind random
>> bind turn
>> Async.RunSynchronously
<| (write "Enter a number:")
0 // return an integer exit code
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment