1
2
3
4
5 package unify
6
7 import (
8 "fmt"
9 "iter"
10 "maps"
11 "slices"
12 )
13
14 type Closure struct {
15 val *Value
16 env envSet
17 }
18
19 func NewSum(vs ...*Value) Closure {
20 id := &ident{name: "sum"}
21 return Closure{NewValue(Var{id}), topEnv.bind(id, vs...)}
22 }
23
24
25 func (c Closure) IsBottom() bool {
26 return c.val.Domain == nil
27 }
28
29
30
31 func (c Closure) Summands() iter.Seq[*Value] {
32 return func(yield func(*Value) bool) {
33 var rec func(v *Value, env envSet) bool
34 rec = func(v *Value, env envSet) bool {
35 switch d := v.Domain.(type) {
36 case Var:
37 parts := env.partitionBy(d.id)
38 for _, part := range parts {
39
40 if !rec(part.value, part.env) {
41 return false
42 }
43 }
44 return true
45 default:
46 return yield(v)
47 }
48 }
49 rec(c.val, c.env)
50 }
51 }
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 func (c Closure) All() iter.Seq[*Value] {
68
69
70
71
72
73
74
75 return func(yield func(*Value) bool) {
76 c.val.all1(c.env, func(v *Value, e envSet) bool {
77 return yield(v)
78 })
79 }
80 }
81
82 func (v *Value) all1(e envSet, cont func(*Value, envSet) bool) bool {
83 switch d := v.Domain.(type) {
84 default:
85 panic(fmt.Sprintf("unknown domain type %T", d))
86
87 case nil:
88 return true
89
90 case Top, String:
91 return cont(v, e)
92
93 case Def:
94 fields := d.keys()
95
96
97
98 parts := make(map[string]*Value, len(fields))
99
100
101
102 var allElt func(elt int, e envSet) bool
103 allElt = func(elt int, e envSet) bool {
104 if elt == len(fields) {
105
106
107 nVal := newValueFrom(Def{maps.Clone(parts)}, v)
108 return cont(nVal, e)
109 }
110
111 return d.fields[fields[elt]].all1(e, func(v *Value, e envSet) bool {
112 parts[fields[elt]] = v
113 return allElt(elt+1, e)
114 })
115 }
116 return allElt(0, e)
117
118 case Tuple:
119
120 if d.repeat != nil {
121
122 return cont(v, e)
123 }
124 parts := make([]*Value, len(d.vs))
125 var allElt func(elt int, e envSet) bool
126 allElt = func(elt int, e envSet) bool {
127 if elt == len(d.vs) {
128
129
130 nVal := newValueFrom(Tuple{vs: slices.Clone(parts)}, v)
131 return cont(nVal, e)
132 }
133
134 return d.vs[elt].all1(e, func(v *Value, e envSet) bool {
135 parts[elt] = v
136 return allElt(elt+1, e)
137 })
138 }
139 return allElt(0, e)
140
141 case Var:
142
143 for _, ePart := range e.partitionBy(d.id) {
144
145
146
147 env := ePart.env.bind(d.id, ePart.value)
148 if !ePart.value.all1(env, cont) {
149 return false
150 }
151 }
152 return true
153 }
154 }
155
View as plain text