Tuesday, March 16, 2010

Latest Semantic Net Experiment

Here it is, the latest and most complex experiment. I'm not sure I'll keep going with this. So far, it does what I intended it to do, but the implementation is shaping up to be way more object-oriented and way less functional than I wanted. And since the whole point here is to learn F# (and especially its use in creating custom languages), I think I may try something else for a change. Perhaps a unification system?

As usual, presented as a learning exercise without warranty or implied fitness; use at your own risk. Also as usual, formatted for the blog window (I have a twin horror of code wrap and horizontal scrolling, lol.)

Main module (test code below):

module SemanticNet

open System.Collections.Generic


let internal findOrNew<'k,'v> (ff:'k->bool*'v)
(fn:unit->'v)
(fa:'k*'v->unit)
(k:'k) =
match ff k with
| (true,v) -> v
| (false,_) ->
let v = fn()
fa(k,v)
v


let internal findOrNewD<'k,'v> (d:Dictionary<'k,'v>)
(fn:unit->'v)
(k:'k) =
findOrNew d.TryGetValue fn d.Add k


let internal findOrNone<'k,'v> (ff:'k->bool*'v)
(k:'k) =
match ff k with
| (true,v) -> Some(v)
| _ -> None


let internal findOrNoneD<'k,'v> (d:Dictionary<'k,'v>)
(k:'k) =
findOrNone d.TryGetValue k



type Entity (graph:Graph, key:string) =
member this.Graph = graph
member this.Key = key



and Link (graph:Graph, key:string) =
inherit Entity(graph,key)



and LinksOut (nodeIn:Node, link:Link) =

let nodesOut = new Dictionary<string,Node>()

let newNodeOut nodeKey =
let nodeOut:Node = nodeIn.Graph.Node nodeKey
nodeOut.AddIn link.Key nodeIn
nodeOut

member this.Node (nodeOutKey:string) =
findOrNewD nodesOut
(fun()->(newNodeOut nodeOutKey))
nodeOutKey // Node

member this.Nodes (nodeOutKeys:string list) =
match nodeOutKeys with
| [] -> nodeIn.Graph
| h::t ->
this.Node h |> ignore
this.Nodes t

member this.TestWrite (p:string->unit) =
p (" "+link.Key+"\n")
for node in nodesOut.Values do
p (" "+node.Key+"\n")

static member (+) ((this:LinksOut),
(nodeKey:string)) =
(this.Node nodeKey).Graph

static member (+) ((this:LinksOut),
(nodeKeys:string list)) =
this.Nodes nodeKeys



and LinksIn (nodeOut:Node, link:Link) =

let nodesIn = new Dictionary<string,Node>()

member internal this.Node (nodeIn:Node) =
if not (nodesIn.ContainsKey nodeIn.Key) then
nodesIn.Add(nodeIn.Key,nodeIn)



and Node (graph:Graph, key:string) =
inherit Entity(graph,key)

let linksOut = new Dictionary<string,LinksOut>()
let linksIn = new Dictionary<string,LinksIn>()

member internal this.AddIn (linkInKey:string) (nodeIn:Node) =
((findOrNewD linksIn
(fun()->(graph.LinksIn this linkInKey))
linkInKey).Node nodeIn) |> ignore

member this.Link (linkOutKey:string) =
findOrNewD linksOut
(fun()->(graph.LinksOut this linkOutKey))
linkOutKey // Links

member this.Links ((linkOutKey:string),(nodeOutKeys:string list)) =
(findOrNewD linksOut
(fun()->(graph.LinksOut this linkOutKey))
linkOutKey).Nodes nodeOutKeys |> ignore
this // Node

member this.TestWrite (p:string->unit) =
p (key+"\n")
for links in linksOut.Values do
links.TestWrite p

static member (+) ((this:Node),
(linkOutKey:string)) =
this.Link linkOutKey

static member (+) ((this:Node),
(linkNodeOut:string*string list)) =
this.Links linkNodeOut



and Graph () =

let links = new Dictionary<string,Link>()
let nodes = new Dictionary<string,Node>()

member internal this.Link linkKey =
findOrNewD links
(fun()->Link(this,linkKey)) linkKey // Link

member internal this.LinksIn node linkKey =
LinksIn(node,(this.Link linkKey))

member internal this.LinksOut node linkKey =
LinksOut(node,(this.Link linkKey))

member this.Node nodeKey =
findOrNewD nodes
(fun()->Node(this,nodeKey))
nodeKey // Node

member this.TestWrite (p:string->unit) =
for node in nodes.Values do
node.TestWrite p

static member (+) ((this:Graph),(nodeKey:string)) =
this.Node nodeKey



Test code:

open System 
open SemanticNet


let g = Graph()

g+"dog"+
("isA",["canine";"man's best friend";"pet"])+
("hasA",["leash";"collar"]) |> ignore

g+"mammal"+"isA"+"animal" |> ignore
g+"canine"+"isA"+"mammal" |> ignore
g+"man's best friend"+"isA"+"dog" |> ignore

g.TestWrite (fun s->Console.Write(s))

Console.ReadLine() |> ignore

No comments: