Skip to content

Instantly share code, notes, and snippets.

@1tgr
Created October 17, 2012 21:28
Show Gist options
  • Select an option

  • Save 1tgr/3908344 to your computer and use it in GitHub Desktop.

Select an option

Save 1tgr/3908344 to your computer and use it in GitHub Desktop.
Demonstrates functions within a graph. Functions don't know about each other; they take dependencies on strongly-typed nodes. We can inspect the structure of the graph separately from evaluating it.
open System
open System.Collections.Generic
type IKey =
interface end
type IKey<'Value> =
inherit IKey
[<AbstractClass>]
type Node() =
let mutable name = ""
abstract Inputs : Node array
abstract Eval : values : obj array -> obj
member t.Name
with get() = name
and set(value) = name <- value
[<AbstractClass>]
type Node<'Value>() =
inherit Node()
type IGraphInputs =
abstract SourceNode<'Key, 'Value when 'Key :> IKey<'Value>> : key : 'Key -> Node<'Value>
module Graph =
let funcNode1 (a : Node<'a>) (f : 'a -> 'b) : Node<'b> =
{ new Node<'b>() with
member t.Inputs = [| a |]
member t.Eval inputs = box (f (unbox inputs.[0]))
}
let funcNode2 (a : Node<'a>) (b : Node<'b>) (f : 'a -> 'b -> 'c) :
Node<'c> =
{ new Node<'c>() with
member t.Inputs = [| a; b |]
member t.Eval inputs = box (f (unbox inputs.[0]) (unbox inputs.[1]))
}
let constNode (f : unit -> 'a) : Node<'a> =
{ new Node<'a>() with
member t.Inputs = [| |]
member t.Eval _ = box (f ())
}
let eval (node : Node) : obj =
let values = Dictionary()
let rec impl (node : Node) =
match values.TryGetValue(node) with
| true, value -> value
| false, _ ->
let inputValues = Array.map impl node.Inputs
let value = node.Eval inputValues
values.[node] <- value
value
impl node
let evalT (node : Node<'Value>) : 'Value =
let node = node :> Node
let value = eval node
value :?> 'Value
type WebPage =
| WebPage of Uri
interface IKey<string>
[<RequireQualifiedAccess>]
type TimeSeries =
{
Ticker : string
FromDate : DateTime
}
interface IKey<double array>
[<RequireQualifiedAccess>]
type Correlation =
{
Ticker1 : string
Ticker2 : string
FromDate : DateTime
}
interface IKey<double>
module Builders =
let correlation (key : Correlation) (inputs : IGraphInputs) =
let k1 : TimeSeries = { Ticker = key.Ticker1; FromDate = key.FromDate }
let k2 : TimeSeries = { Ticker = key.Ticker2; FromDate = key.FromDate }
Graph.funcNode2 (inputs.SourceNode k1) (inputs.SourceNode k2) <| fun ts1 ts2 ->
// TODO: calculate serial correlation
1.0
let timeSeries (key : TimeSeries) (inputs : IGraphInputs) =
let url = sprintf "http://ichart.yahoo.com/table.csv?s=%s&a=%d&b=%d&c=%d" key.Ticker (key.FromDate.Month - 1) key.FromDate.Day key.FromDate.Year
let k = WebPage (Uri(url))
Graph.funcNode1 (inputs.SourceNode k) <| fun text ->
// TODO: parse web page
[| 1.0; 2.0; 3.0 |]
let webPage (WebPage uri) (_ : IGraphInputs) =
Graph.constNode <| fun () ->
// TODO: fetch web page
""
let rec buildGraph (nodes : IDictionary<IKey, Node>) (key : IKey) : Node =
match nodes.TryGetValue(key) with
| true, node -> node
| false, _ ->
let inputs =
{ new IGraphInputs with
member t.SourceNode<'Key, 'Value when 'Key :> IKey<'Value>> (k : 'Key) : Node<'Value> =
buildGraphT nodes k
}
let node =
match key with
| :? Correlation as c -> Builders.correlation c inputs :> Node
| :? TimeSeries as ts -> Builders.timeSeries ts inputs :> Node
| :? WebPage as wp -> Builders.webPage wp inputs :> Node
| _ -> failwithf "Don't know how to build %O %A" (key.GetType()) key
node.Name <- (sprintf "%A" key).Replace("\n", "")
nodes.[key] <- node
node
and buildGraphT<'Key, 'Value when 'Key :> IKey<'Value>> (nodes : IDictionary<IKey, Node>) (key : 'Key) : Node<'Value> =
let key = key :> IKey
let node = buildGraph nodes key
node :?> Node<'Value>
let nodes = Dictionary()
let node = buildGraphT nodes ({ Ticker1 = "GOOG"; Ticker2 = "AAPL"; FromDate = DateTime.Today.AddYears(-1) } : Correlation)
for pair in nodes do
printfn "Dependencies for %s:" pair.Value.Name
for inputNode in pair.Value.Inputs do
printfn "\tneeds %s" inputNode.Name
let result = Graph.evalT node
printfn "Result = %f" result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment