-
Notifications
You must be signed in to change notification settings - Fork 2
/
std-lib.bot
263 lines (222 loc) · 7.42 KB
/
std-lib.bot
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
(define-macro ; "Always returns nil." (lambda (x ...) ()))
(define nil "Equivalent to an empty list." '())
(define nil?
"Returns true if argument is nil."
(lambda (x) (equal? nil x)))
(define identity "Returns what is passed in." (lambda (x) x))
(; define-macro apply
"Takes a fn and an arr and applies the elements of the array to the function as arguments."
(lambda (fn arr) `(~fn ~@arr))
)
(define list "Takes variadic arguments that are returned wrapped in a list."
(lambda (args ...) args))
(define type? "Checks if the type of the first argument is equal to the string passed as a second arg."
(lambda (var type) (equal? (typeof var) type)))
(define-macro cond
"Takes a set of test/expr pairs. It evaluates each test one at a
time. If a test returns logical true, cond evaluates and returns
the value of the corresponding expr and doesn't evaluate any of the
other tests or exprs."
(lambda (x rest ...)
`(if ~(car x)
~(car (cdr x))
(if ~(nil? rest)
()
(cond ~@rest)))))
(define car'
"Takes a list of lists, and maps car onto it."
(lambda (arrs)
(if (nil? arrs)
nil
(cons
(car (car arrs))
(car' (cdr arrs))
)
)
))
(define cdr'
"Takes a list of lists, and maps cdr onto it."
(lambda (arrs)
(if (nil? arrs)
nil
(cons (cdr (car arrs)) (cdr' (cdr arrs)))
)
))
(define-macro and
"Evaluates arguments from left to right until it hits one that evaluates to false. If all of expressions evaluate to true, it will return true. Otherwise it will return false."
(lambda (x args ...)
(if (nil? args)
x
`(if ~x (and ~@args) false))))
(define-macro or
"Evaluates arguments from left to right until it hits one that evaluates to true. If one of the expressions evaluate to true, it will return true. Otherwise it will return false."
(lambda (x args ...)
(if (nil? args)
x
`(if ~x true (or ~@args)))))
(define has-nil?
"Returns true if the passed-in list contains nil."
(lambda (arr)
(if (nil? arr)
false
(or (nil? (car arr)) (has-nil? (cdr arr)))
)
))
(define map
"Should be called with at least one array."
(lambda (fn arrs ...)
(cond
((nil? arrs) "Call map with at least one array.")
((has-nil? arrs) nil)
(true (concat (list (apply fn (car' arrs))) (apply map (cons fn (cdr' arrs)))))
)
))
(define foldr (lambda (fn base lst)
(if (nil? lst)
base
(fn (foldr fn base (cdr lst)) (car lst)))))
(define foldl (lambda (fn base lst)
(if (nil? lst)
base
(foldl fn
(fn base (car lst))
(cdr lst)))))
(define reduce (lambda (fn base arrs ...)
(cond
((nil? arrs) "Call reduce with at least one array.")
((has-nil? arrs) base)
(true (apply fn (cons (apply reduce (cons fn (cons base (cdr' arrs)))) (car' arrs))))
)
))
(define reverse "Reverses the passed-in list." (lambda (l) (foldr (lambda (a v) (concat a (list v))) '() l)))
(define filter (lambda (pred arr)
(foldr (lambda (acc v)
(if (pred v)
(cons v acc)
acc
)
) '() arr))
)
(define zero?
"Returns true if the argument is equal to 0."
(lambda (expr)
(equal? 0 expr)))
(define not
"Returns the negated argument. Equivalent to (if expr false true)"
(lambda (expr)
(if expr false true)))
(define second
"Returns the second element of the passed-in list. Equivalent to (car (cdr lst))"
(lambda (x)
(car (cdr x))))
(define contain? (lambda (fn key arr)
(foldr (lambda (acc v) (or acc (equal? key (fn v)))) false arr)))
(define len (lambda (coll)
(foldr (lambda (acc _) (+ acc 1)) 0 coll)))
(define dedupe (lambda (arr) (foldr (lambda (acc x) (if (contain? identity x acc) acc (cons x acc))) '() arr)))
(define even-len? (lambda (coll)
(if (nil? coll)
true
(not (even-len? (cdr coll))))))
(define every-other-odd
(lambda (coll)
(if (nil? coll)
()
(if (even-len? coll)
(every-other-odd (cdr coll))
(cons (car coll) (every-other-odd (cdr coll)))))))
(define every-other-even
(lambda (coll)
(if (nil? coll)
()
(if (even-len? coll)
(cons (car coll) (every-other-even (cdr coll)))
(every-other-even (cdr coll))))))
(; define-macro let
"Todo"
(lambda (vars body)
`((lambda ~(every-other-even vars) ~body) ~@(every-other-odd vars))))
(define-macro ->>
"Usage: (->> x & funcs)
Threads the expr through the lambdas. Inserts x as the last item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the last item in second form, etc. (from clojuredocs)"
(lambda (data rest ...)
`(cond
(~(nil? rest) ~data)
(~(nil? (cdr rest)) (~@(car rest) ~data))
(true (->> (~@(car rest) ~data) ~@(cdr rest))))))
(define-macro ->
"Usage: (-> x & forms)
Threads the expr through the forms. Inserts x as the second item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the second item in second form, etc. (from clojuredocs)"
(lambda (data rest ...)
`(cond
(~(nil? rest) ~data)
(~(nil? (cdr rest)) (~(car (car rest)) ~data ~@(cdr (car rest))))
(true (-> (~@(car rest) ~data) ~@(cdr rest))))))
(define nth
(lambda (lst n)
(if (zero? n)
(car lst)
(nth (cdr lst) (- n 1)))))
(define remove-nth
(lambda (list n)
(if (zero? n)
(cdr list)
(cons (car list) (remove-nth (cdr list) (- n 1)))
)))
(define last (lambda (lst)
(cond
((nil? lst) lst)
((nil? (cdr lst)) (car lst))
(true (last (cdr lst)))
)
))
(define do
(lambda (args ...) (last args)))
(define range (lambda (fst args ...)
(if (nil? args)
(range 0 fst)
(if (equal? fst (car args))
nil
(cons fst (range (+ 1 fst) (car args)))
)
)
))
(define assoc
"Takes a hashmap, a key and a value, and returns a hashmap with the (key value) pair added to it ."
(let (hm-dedupe (lambda (map)
(foldl (lambda (acc k)
(if (contain? (lambda (e) (car e)) (car k) acc)
acc
(cons k acc)
) )
'()
map
)
))
(lambda (hmap key val)
(let (m (hm-dedupe (cons (list key val) (hmap))))
(lambda (args ...)
(let (l (len args))
(cond ((equal? 0 l) m)
((equal? 1 l) (foldr (lambda (acc v)
(if (equal? (car v) (car args))
(car (cdr v))
acc)) '() m)))))))))
(define hashmap
"Creates a hashmap. Can be followed by alternating keys and values to initialize it."
(lambda (init ...)
(foldr (lambda (prevhm tup) (apply assoc (cons prevhm tup))) (lambda (a ...) '()) init)))
(define dissoc
"Takes a hashmap and an arbitrary number of keys, and returns a hashmap with the keys removed."
(lambda (hmap keys ...)
(let (m (filter (lambda (v) (not (contain? identity (car v) keys))) (hmap)))
(lambda (args ...)
(let (l (len args))
(cond ((equal? 0 l) m)
((equal? 1 l) (foldr (lambda (acc v)
(if (equal? (car v) (car args))
(car (cdr v))
acc)) '() m))))))))
(define update!
(lambda (some-ref fn)
(set! some-ref (fn (get some-ref)))))