Skip to content

Commit 38fa8b2

Browse files
committed
Fixed name clashes with free variables
1 parent 23c675f commit 38fa8b2

File tree

2 files changed

+57
-13
lines changed

2 files changed

+57
-13
lines changed

lambda/lamterm.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type Term interface {
1414
substitute(Var, Term) Term
1515

1616
String() string
17-
deDeBruijn(*strings.Builder, *[]string, *int)
17+
deDeBruijn(*strings.Builder, *[]string, *int, *[]Free)
1818

1919
Reduce() (Term, error)
2020
NorReduce() (Term, error)

lambda/stringify.go

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,34 +23,61 @@ func intToLetter(num int) string {
2323
return "x" + strconv.Itoa(num-25)
2424
}
2525

26+
func getFreeVariables(t Term) []Free {
27+
switch t := t.(type) {
28+
case Free:
29+
return []Free{t}
30+
31+
case Appl:
32+
return append(getFreeVariables(t[0]), getFreeVariables(t[1])...)
33+
34+
case Abst:
35+
return getFreeVariables(t[0])
36+
37+
default:
38+
return []Free{}
39+
}
40+
}
41+
42+
func in(t Free, f *[]Free) bool {
43+
for _, v := range *f {
44+
if t == v {
45+
return true
46+
}
47+
}
48+
49+
return false
50+
}
51+
2652
// String returns the Lambda Expression as a string
2753
func (lx Appl) String() string {
2854
builder := strings.Builder{}
29-
lx.deDeBruijn(&builder, new([]string), new(int))
55+
freeVars := getFreeVariables(lx)
56+
lx.deDeBruijn(&builder, new([]string), new(int), &freeVars)
3057

3158
return builder.String()
3259
}
3360

34-
func (lx Appl) deDeBruijn(builder *strings.Builder, boundLetters *[]string, nextletter *int) {
61+
func (lx Appl) deDeBruijn(builder *strings.Builder, boundLetters *[]string, nextletter *int, freeVars *[]Free) {
3562
for i, part := range lx {
3663
switch part := part.(type) {
3764
case Abst:
3865
builder.WriteByte('(')
39-
part.deDeBruijn(builder, boundLetters, nextletter)
66+
part.deDeBruijn(builder, boundLetters, nextletter, freeVars)
4067
builder.WriteByte(')')
4168

4269
case Appl:
4370
if i == 0 {
44-
part.deDeBruijn(builder, boundLetters, nextletter)
71+
part.deDeBruijn(builder, boundLetters, nextletter, freeVars)
4572

4673
} else {
4774
builder.WriteByte('(')
48-
part.deDeBruijn(builder, boundLetters, nextletter)
75+
part.deDeBruijn(builder, boundLetters, nextletter, freeVars)
4976
builder.WriteByte(')')
5077
}
5178

5279
default:
53-
part.deDeBruijn(builder, boundLetters, nextletter)
80+
part.deDeBruijn(builder, boundLetters, nextletter, freeVars)
5481
}
5582

5683
// Put space between first and second part
@@ -63,25 +90,33 @@ func (lx Appl) deDeBruijn(builder *strings.Builder, boundLetters *[]string, next
6390
// String returns the lambda abstraction as a string
6491
func (la Abst) String() string {
6592
builder := strings.Builder{}
66-
la.deDeBruijn(&builder, new([]string), new(int))
93+
freeVars := getFreeVariables(la)
94+
la.deDeBruijn(&builder, new([]string), new(int), &freeVars)
6795

6896
return builder.String()
6997
}
7098

71-
func (la Abst) deDeBruijn(builder *strings.Builder, boundLetters *[]string, nextletter *int) {
99+
func (la Abst) deDeBruijn(builder *strings.Builder, boundLetters *[]string, nextletter *int, freeVars *[]Free) {
72100
// Remember at which character we were
73101
oldNextLetter := *nextletter
74102

75-
// Add the localy bound letter to the list
103+
// Search for a free name
76104
newLetter := intToLetter(*nextletter)
77105
*nextletter++
106+
107+
for in(Free(newLetter), freeVars) {
108+
newLetter = intToLetter(*nextletter)
109+
*nextletter++
110+
}
111+
112+
// Add the localy bound letter to the list
78113
*boundLetters = append([]string{newLetter}, *boundLetters...)
79114

80115
builder.WriteRune('λ')
81116
builder.WriteString(newLetter)
82117
builder.WriteByte('.')
83118

84-
la[0].deDeBruijn(builder, boundLetters, nextletter)
119+
la[0].deDeBruijn(builder, boundLetters, nextletter, freeVars)
85120

86121
// Remove our local naming
87122
*boundLetters = (*boundLetters)[1:]
@@ -94,20 +129,29 @@ func (lv Var) String() string {
94129
return intToLetter(0)
95130
}
96131

97-
func (lv Var) deDeBruijn(builder *strings.Builder, boundLetters *[]string, nextletter *int) {
132+
func (lv Var) deDeBruijn(builder *strings.Builder, boundLetters *[]string, nextletter *int, freeVars *[]Free) {
98133
if int(lv) < len(*boundLetters) && (*boundLetters)[lv] != "" {
99134
builder.WriteString((*boundLetters)[lv])
100135
return
101136
}
102137

138+
// Search for a free name
103139
newLetter := intToLetter(*nextletter)
104140
*nextletter++
105141

142+
for in(Free(newLetter), freeVars) {
143+
newLetter = intToLetter(*nextletter)
144+
*nextletter++
145+
}
146+
147+
// Add it to the boundletters table
106148
for i := len(*boundLetters); i < int(lv); i++ {
107149
*boundLetters = append(*boundLetters, "")
108150
}
109151

110152
*boundLetters = append(*boundLetters, newLetter)
153+
154+
// And finaly write it to output
111155
builder.WriteString(newLetter)
112156
}
113157

@@ -117,6 +161,6 @@ func (lf Free) String() string {
117161
return string(lf)
118162
}
119163

120-
func (lf Free) deDeBruijn(builder *strings.Builder, boundLetters *[]string, nextletter *int) {
164+
func (lf Free) deDeBruijn(builder *strings.Builder, boundLetters *[]string, nextletter *int, freeVars *[]Free) {
121165
builder.WriteString(string(lf))
122166
}

0 commit comments

Comments
 (0)