-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathtrain.go
More file actions
125 lines (111 loc) · 2.49 KB
/
Copy pathtrain.go
File metadata and controls
125 lines (111 loc) · 2.49 KB
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
123
124
125
package apl
import (
"fmt"
"strings"
)
// Train is a function train expression.
// It does not contain it's arguments like a Primitive or a fnVar.
// See DyaProg p 25.
type train []expr
func (t train) Eval(a *Apl) (Value, error) {
return t, nil
}
func (t train) String(f Format) string {
v := make([]string, len(t))
for i := range t {
v[i] = t[i].String(f)
}
return "(" + strings.Join(v, ", ") + ")"
}
func (t train) Copy() Value { return t }
func (t train) Call(a *Apl, L, R Value) (Value, error) {
if len(t) < 2 {
return nil, fmt.Errorf("cannot call short train, length %d", len(t))
} else if len(t)%2 == 0 {
// even number: f g h i j k → f(g h(i j k)) ⍝ atop(fork(fork))
f := atop{}
end := 1
if len(t) == 2 {
end = 2
}
for i, e := range t[:end] {
if v, err := e.Eval(a); err != nil {
return nil, err
} else {
f[i] = v
}
}
if len(t) > 3 {
f[1] = train(t[1:])
}
return f.Call(a, L, R)
} else {
// odd number: e f g h i j k → e f(g h(i j k)) ⍝ fork(fork(fork))
f := fork{}
end := 2
if len(t) == 3 {
end = 3
}
for i, e := range t[:end] {
if v, err := e.Eval(a); err != nil {
return nil, err
} else {
f[i] = v
}
}
if len(t) > 3 {
f[2] = train(t[2:])
}
return f.Call(a, L, R)
}
}
type atop [2]Value
func (t atop) String(f Format) string {
return fmt.Sprintf("(%s %s)", t[0].String(f), t[1].String(f))
}
func (t atop) Call(a *Apl, L, R Value) (Value, error) {
g, ok := t[0].(Function)
if ok == false {
return nil, fmt.Errorf("atop: expected function g: %T", t[0])
}
h, ok := t[1].(Function)
if ok == false {
return nil, fmt.Errorf("atop: expected function h: %T", t[1])
}
// L may be nil.
v, err := h.Call(a, L, R)
if err != nil {
return nil, err
}
return g.Call(a, nil, v)
}
type fork [3]Value
func (fk fork) String(f Format) string {
return fmt.Sprintf("(%s %s %s)", fk[0].String(f), fk[1].String(f), fk[2].String(f))
}
func (fk fork) Call(a *Apl, L, R Value) (Value, error) {
f, fok := fk[0].(Function)
g, ok := fk[1].(Function)
if ok == false {
return nil, fmt.Errorf("fork: expected function g: %T", fk[1])
}
h, ok := fk[2].(Function)
if ok == false {
return nil, fmt.Errorf("fork: expected function h: %T", fk[2])
}
// Agh fork if f is not a function.
var l Value
l = fk[0]
if fok {
if v, err := f.Call(a, L, R); err != nil { // TODO copy?
return nil, err
} else {
l = v
}
}
r, err := h.Call(a, L, R) // TODO copy?
if err != nil {
return nil, err
}
return g.Call(a, l, r)
}