-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLibrary.fs
123 lines (112 loc) · 3.47 KB
/
Library.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
namespace Kanren
module Stream =
open System.Collections
open System.Collections.Generic
type Stream<'a> =
| Nil
| Cons of 'a * Stream<'a>
| Thunk of Lazy<Stream<'a>>
member this.toSeq () =
match this with
| Nil -> Seq.empty
| Cons (x,xs) -> seq { x; yield! xs}
| Thunk t -> seq { yield! t.Force().toSeq() }
interface IEnumerable with
member this.GetEnumerator() =
this.toSeq().GetEnumerator()
interface IEnumerable<'a> with
member this.GetEnumerator() =
this.toSeq().GetEnumerator()
let just x = Cons (x,Nil)
let rec mplus m1 m2 =
match m1 with
| Nil -> m2
| Cons (x,xs) -> Cons (x, mplus m2 xs)
| Thunk t -> Thunk (lazy (mplus m2 (t.Force())))
let rec bind m f =
match m with
| Nil -> Nil
| Cons(x,xs) -> mplus (f x) (bind xs f)
| Thunk t -> Thunk (lazy (bind (t.Force()) f))
module Logic =
open Stream
open FSharpPlus
open FSharpPlus.Data
open FSharp.Quotations
open FSharp.Quotations.Evaluator
type Term<'a> =
| Var of int
| Value of 'a
| Pair of Term<'a> * Term<'a>
| Empty
type Subst<'a> = Subst of Map<int, Term<'a>> * int
type Goal<'a> = State<Subst<'a>,Stream<Subst<'a>>>
let fresh () : State<Subst<'a>,Term<'a>> =
monad {
let! Subst (s,x)= get
do! put (Subst (s,x+1))
return (Var x)
}
let rec walk v m =
match v with
| Value a -> Value a
| Empty -> Empty
| Pair (a,b) -> Pair (walk a m, walk b m)
| Var i ->
match Map.tryFind i m with
| Some v' -> walk v' m
| None -> Var i
let conj m (n: Goal<'a>) : Goal<'a> =
monad {
let! (x: Stream<Subst<'a>>) = m
Stream.bind x (fun s -> State.eval n s)
}
let rec unify (u: Term<'a>) (v:Term<'a>) : Goal<'a> =
monad {
let! Subst (m, c) = get
match walk u m, walk v m with
| Value a, Value b ->
if a = b then
just (Subst (m,c))
else
Stream.Nil
| Var a, Var b ->
if a = b then
just (Subst (m,c))
else
Stream.Nil
| a, Var i
| Var i, a ->
just (Subst (Map.add i a m, c))
| Empty, Empty -> just (Subst (m,c))
| Pair(a1,b1), Pair(a2,b2) ->
return! conj (unify a1 a2) (unify b1 b2)
| _ -> Stream.Nil
}
let eq u v = unify u (Value v)
let disj m n : Goal<'a> =
monad {
let! (x:Stream<Subst<'a>>) = m
let! (y: Stream<Subst<'a>>) = n
mplus x y
}
let disjP exprs =
exprs |> Seq.reduce disj
let conjP exprs =
exprs |> Seq.reduce conj
let conde branches =
branches
|> Seq.map conjP
|> disjP
let neq u v =
monad {
let! matches = unify u v
let! s = get
if matches |> Seq.length > 0 then
return Stream.Nil
else
return just s
}
let run l = State.eval l (Subst (Map.empty, 0))
let delay (x: Expr<Goal<'a>>) =
QuotationEvaluator.Evaluate <@ (State (fun s -> Thunk (lazy (State.eval (%x) s)), s)) @>