Created
October 17, 2012 21:28
-
-
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.
This file contains hidden or 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
| 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