Last active
December 14, 2015 23:19
-
-
Save kirelagin/5164431 to your computer and use it in GitHub Desktop.
Reading graphs (and any other inputs) with enhanced State monad using F#'s Computation Expressions' awesomeness.
This file contains 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
//// State monad (on F# steroids) | |
type State<'s, 'a> = State of ('s -> 'a * 's) | |
let runState (State f) = f | |
type StateBuilder() = | |
member __.Return (x : 'a) : State<'s, 'a> = State <| fun st -> (x, st) | |
member __.Bind (p : State<'s, 'a>, (f : 'a -> State<'s, 'b>)) : State<'s, 'b> = | |
State <| fun st -> let (v, ns) = runState p st in runState (f v) ns | |
// This makes `for` work | |
member __.Delay f = f() | |
member __.Combine (a, b) = __.Bind(a, fun () -> b) | |
member __.For (s, f) = Seq.fold (fun m1 i -> __.Combine(m1, f i)) (__.Return ()) s | |
member __.Zero () = __.Return () | |
let state = StateBuilder() | |
let getState<'s> : State<'s,'s> = State <| fun s -> (s, s) | |
let putState<'s, 'a> v : State<'s, unit> = State <| fun _ -> ((), v) | |
//// | |
//// Parsing full of F# awesomeness | |
type Parse<'a> = State<seq<string>, 'a> | |
type ParseBuilder(path : string) = | |
inherit StateBuilder() | |
let fileTokens = seq { | |
use sr = new System.IO.StreamReader(path) | |
while not sr.EndOfStream do | |
yield! sr.ReadLine().Split([| ' ' |], System.StringSplitOptions.RemoveEmptyEntries) | |
} | |
member __.Run (p : Parse<'a>) : 'a = let (v, _) = runState p fileTokens in v | |
let parse path = ParseBuilder(path) | |
let nextToken = state { | |
let! t = getState | |
do! putState (Seq.skip 1 t) | |
return Seq.head t | |
} | |
//// | |
let parseInt = System.Int32.Parse (* useful shortcut *) | |
type Node (id : int) = | |
let mutable edges : Edge list = [] | |
member __.Edges with get() = edges and set(value) = edges <- value | |
member this.AddEdgeTo other = edges <- Edge (this, other) :: edges; | |
override __.ToString () = sprintf "Node #%d" (id+1) | |
and Edge (source : Node, target : Node) = | |
override __.ToString () = sprintf "Edge from %s to %s" (source.ToString()) (target.ToString()) | |
let readGraph n m : Parse<Node[]> = state { | |
let vertices = Array.init n (fun i -> Node i) | |
for j in [0 .. m-1] do | |
let! f = nextToken | |
let! t = nextToken | |
vertices.[parseInt f - 1].AddEdgeTo(vertices.[parseInt t - 1]) | |
return vertices | |
} | |
[<EntryPoint>] | |
let main argv = | |
let (n, m, g) = parse "graphgame.in" { | |
let! nt = nextToken | |
let! mt = nextToken | |
let (n, m) = (parseInt nt, parseInt mt) | |
let! graph = readGraph n m | |
return (n, m, graph) | |
} | |
// do cool stuff with that graph | |
0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment