-
Notifications
You must be signed in to change notification settings - Fork 0
/
hof.go
183 lines (163 loc) · 3.05 KB
/
hof.go
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package ops
import (
"slices"
"strings"
"github.com/blackchip-org/zc/v5/pkg/zc"
)
/*
oper apply
func Apply args:Val* fn:Str nargs:Int -- Val*
title Apply a function using arguments on stack
desc
Evaluates the expression in *fn* by first popping *nargs* off the stack and
pushing them back as a single argument. This is useful for higher order
functions, like map, where some of the arguments are from existing results
found on the stack.
end
example
1 2 3 4 -- 1 | 2 | 3 | 4
n -- 1 | 2 | 3 | 4 | 4 # size
[swap sub] [map] 2 apply -- 3 | 2 | 1 | 0
end
*/
func Apply(c zc.Calc) {
nArgs := zc.PopInt(c)
fnName := zc.PopString(c)
if c.StackLen() < nArgs {
zc.ErrNotEnoughArgs(c, "apply", nArgs)
return
}
var args []string
for i := 0; i < nArgs; i++ {
args = slices.Insert(args, 0, zc.PopString(c))
}
c.Push(strings.Join(args, " "))
c.Eval(fnName)
}
/*
oper eval
func Eval expr:Str -- Val*
title Evaluate top of stack
desc
Evaluate *expr* as if it was input to the calculator.
end
example
[1 2 add -- 1 2 add
eval -- 3
end
*/
func Eval(c zc.Calc) {
fn := zc.PopString(c)
c.Eval(fn)
}
/*
oper filter
func Filter Val* expr:Str -- Val*
title Filter items in the stack
desc
Filter the stack by keeping items that are true when evaluated by
expression *expr*.
end
example
1 2 3 4 5 6 -- 1 | 2 | 3 | 4 | 5 | 6
[2 mod 0 eq] filter -- 2 | 4 | 6
end
*/
func Filter(c zc.Calc) {
var rs []string
fn := zc.PopString(c)
for _, v := range c.Stack() {
dc := c.Derive()
dc.Push(v)
dc.Eval(fn)
out, ok := dc.Pop()
if !ok {
zc.ErrInvalidFunc(c, fn, "no results")
return
}
r, ok := zc.Bool.Parse(out)
if !ok {
zc.ErrExpectedType(c, zc.Bool, out)
return
}
if r {
rs = append(rs, v)
}
}
c.SetStack(rs)
}
/*
oper fold
func Fold Val* expr:Str -- Val
alias reduce
title Reduce items to a single value
desc
Reduce the stack to a single value using the expression *expr*. An
'invalid function' error is raised if *expr* does not reduce.
end
example
1 2 3 4 5 -- 1 | 2 | 3 | 4 | 5
[add] fold -- 15
end
*/
func Fold(c zc.Calc) {
fn := zc.PopString(c)
for c.StackLen() > 1 {
before := c.StackLen()
c.Eval(fn)
if c.Error() != nil {
return
}
if c.StackLen() >= before {
zc.ErrInvalidFunc(c, fn, "does not reduce")
return
}
}
}
/*
oper map
func Map Val* expr:Str -- Val*
title Apply a function to each item on the stack
desc
Apply expression *expr* to each value in the stack.
end
example
1 2 3 4 5 -- 1 | 2 | 3 | 4 | 5
[2 mul] map -- 2 | 4 | 6 | 8 | 10
end
*/
func Map(c zc.Calc) {
var rs []string
fn := zc.PopString(c)
for _, a := range c.Stack() {
dc := c.Derive()
dc.Push(a)
if err := dc.Eval(fn); err != nil {
c.SetError(err)
return
}
if r0, ok := dc.Pop(); ok {
rs = append(rs, r0)
}
}
c.SetStack(rs)
}
/*
oper repeat
func Repeat expr:Val n:Int -- Val*
title Repeat the execution of a function
desc
Repeat execution of expression *expr* for *n* times.
end
example
1 -- 1
[2 mul] 8 repeat -- 256
end
*/
func Repeat(c zc.Calc) {
n := zc.PopInt(c)
fn := zc.PopString(c)
for i := 0; i < n; i++ {
c.Eval(fn)
}
}