Skip to content

Instantly share code, notes, and snippets.

@kirelagin
Last active December 14, 2015 23:19
Show Gist options
  • Save kirelagin/5164431 to your computer and use it in GitHub Desktop.
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.
//// 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