This approach has its pluses and minuses.
On the plus side, F# operator definition makes for a very clean, declarative semantic program. The fact that nodes and links have become instances also makes the code fairly straightforward and efficient.
On the minus side, extending the system at runtime would entail the use of reflection. Also, there is not simple repository for the entities that we can treat as a first class entity, meaning that things like reflection become more difficult and may entail reflection.
So, before going any further and adding things like search, I’ll present this version and then follow up with a version in which entities are represented as data. Then, I’ll pick one and move forward.
Standard disclaimer: presented without warranty or implied suitability of any kind, use at your own risk. And, as always, this is formatted for my narrow blog window, and I present it as a learning exercise, not necessarily either the best way to do F# or the best way to do A.I.
open System.Collections.Generic
[<AbstractClass>]
type Entity (key:string) =
member this.Key = key
type Link (key:string) =
inherit Entity(key)
type Node (key:string) =
inherit Entity(key)
let links = new Dictionary<Link,HashSet<Node>>()
let props = new Dictionary<Node,HashSet<Node>>()
member private this.TryAdd<'a>
(d:Dictionary<'a,HashSet<Node>>) a =
match d.TryGetValue a with
| (false,_) ->
let h = new HashSet<Node>()
d.Add(a,h)
h
| (true,h) -> h
member private this.TrySub<'a>
(d:Dictionary<'a,HashSet<Node>>) a n =
match d.TryGetValue a with
| (false,_) -> false
| (true,h) ->
let rtn = h.Remove n
if (h.Count=0) then
h.Clear()
d.Remove(a) |> ignore
true
member private this.TryClear<'a>
(d:Dictionary<'a,HashSet<Node>>) a =
match d.TryGetValue a with
| (false,_) -> false
| (true,h) ->
h.Clear()
d.Remove(a) |> ignore
true
member private this.Add ((l,n):Link*Node) =
(this.TryAdd links l).Add n |> ignore
this
member private this.Add ((l:Link),(nl:Node list)) =
match nl with
| [] -> this
| h::t ->
(this.TryAdd links l).Add h |> ignore
this.Add(l,t)
member private this.Add ((n0,n1):Node*Node) =
(this.TryAdd props n0).Add n1 |> ignore
this
member private this.Sub ((l,n):Link*Node) =
this.TrySub links l n |> ignore
this
member private this.Sub ((n0,n1):Node*Node) =
this.TrySub props n0 n1 |> ignore
this
member private this.Sub (l:Link) =
this.TryClear links l |> ignore
this
member private this.Sub (n:Node) =
this.TryClear props n |> ignore
this
static member (+=) ((n:Node),(ln:Link*Node)) =
n.Add ln
static member (+=)
((n:Node),((l,nl):Link*(Node list))) =
n.Add(l,nl)
static member (+=) ((n:Node),(nn:Node*Node)) =
n.Add nn
static member (-=) ((n:Node),(ln:Link*Node)) =
n.Sub ln
static member (-=) ((n:Node),(nn:Node*Node)) =
n.Sub nn
static member (-=) ((n:Node),(l:Link)) =
n.Sub l
static member (-=) ((n0:Node),(n1:Node)) =
n0.Sub n1
let isA = Link "isA"
let hasA = Link "hasA"
let animal = Node "animal"
let canine = Node "dog"
let color = Node "color"
let gray = Node "gray"
let mammal = Node "mammal"
let name = Node "name"
let pet = Node "pet"
let spot = Node "spot"
let tail = Node "tail"
let wine = Node "wine"
let white = Node "white"
let wolfie = Node "wolfie"
white += (isA,[color;name;wine]) |> ignore
white -= (isA,name) -= (isA,wine) |> ignore
gray += (isA,color) |> ignore
mammal += (isA,animal) |> ignore
canine += (isA,mammal) += (hasA,tail) |> ignore
spot
+= (isA,canine)
+= (color,white)
+= (isA,pet) |> ignore
wolfie += (isA,canine) |> ignore
wolfie += (color,gray+=(isA,color)) |> ignore
No comments:
Post a Comment