Skip to content

Commit 1d0c18e

Browse files
committed
feat(algorithms): adding identity, recombine to Functional ; min, max and size to List
1 parent 68a23da commit 1d0c18e

File tree

4 files changed

+138
-28
lines changed

4 files changed

+138
-28
lines changed

Functional.ark

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,35 @@
3333

3434
# @brief Flip the arguments of a function
3535
# @param _f the function
36-
# @param _a the first argument
37-
# @details Returns a function taking 1 argument: the second argument of the function to flip
36+
# @details Returns a function taking 2 arguments a and b, calling (f b a)
3837
# =begin
3938
# (let foo (fun (a b) (- a b)))
40-
# ((flip foo 14) 12) # will call (foo 12 14) instead of (foo 14 12)
39+
# ((flip foo) 14 12) # will call (foo 12 14) instead of (foo 14 12)
4140
# =end
4241
# @author https://github.com/rstefanic
43-
(let flip (fun (_f _a)
44-
(fun (_b &_f &_a) (_f _b _a))))
42+
(let flip (fun (_f)
43+
(fun (_a _b &_f) (_f _b _a))))
44+
45+
# @brief No-op, return the value as-is
46+
# @param _x the value
47+
# =begin
48+
# (let maybeAbs (if shouldNormalizeNegatives math:abs identity))
49+
# (let data (list:map nums maybeAbs))
50+
# =end
51+
# @author https://github.com/SuperFola
52+
(let identity (fun (_x) _x))
53+
54+
# @brief Generic form for functions that need to reuse their arguments
55+
# @param _f function called with two arguments
56+
# @param _g first unary function
57+
# @param _h second unary function
58+
# @details Returns a function taking one argument x, calling (f (g x) (h x))
59+
# =begin
60+
# (let mean (recombine (fun (a b) (/ a b)) list:sum list:size))
61+
# (print (mean [0 1 1 2 3 5 8 13])) # 4.125
62+
# =end
63+
# @author https://github.com/SuperFola
64+
(let recombine (fun (_f _g _h)
65+
(fun (_x &_f &_g &_h)
66+
(_f (_g _x) (_h _x)))))
67+

List.ark

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@
4848
# @author https://github.com/SuperFola
4949
(let fill (fun (_val _count) (builtin__list:fill _val _count)))
5050

51+
# @brief Function to call the `len` operator on a list
52+
# @param _L list to get the size of
53+
# =begin
54+
# (print (list:size [1 2 3 4])) # 4
55+
# =end
56+
# @author https://github.com/SuperFola
57+
(let size (fun (_L) (len _L)))
58+
5159
# @brief Modify a given list and return a new one
5260
# @details The original list is not modified
5361
# @param list the list to modify
@@ -62,7 +70,7 @@
6270
# @brief Iterate over a given list and run a given function on every element.
6371
# @param _L the list to iterate over
6472
# @param _func the function to call on each element
65-
# @details The original list is left unmodified.
73+
# @details The original list is not modified.
6674
# =begin
6775
# (import std.List)
6876
# (let collection [1 2 5 12])
@@ -81,7 +89,7 @@
8189

8290
# @brief Iterate over a given list and multiply all the elements with the others.
8391
# @param _L the list to iterate over
84-
# @details The original list is left unmodified.
92+
# @details The original list is not modified.
8593
# =begin
8694
# (import std.List)
8795
# (let collection [1 2 5 12])
@@ -99,7 +107,7 @@
99107

100108
# @brief Iterate over a given list and sum all the elements.
101109
# @param _L the list to iterate over
102-
# @details The original list is left unmodified.
110+
# @details The original list is not modified.
103111
# =begin
104112
# (import std.List)
105113
# (let collection [1 2 5 12])
@@ -115,12 +123,46 @@
115123
(set _index (+ 1 _index)) })
116124
_output }))
117125

126+
# @brief Find the minimum in a list of numbers
127+
# @param _L list of numbers
128+
# @details The original list is not modified.
129+
# =begin
130+
# (let value (list:min [0 1 2 3 5 8])) # 0
131+
# =end
132+
# @author https://github.com/SuperFola
133+
(let min (fun (_L) {
134+
(mut _index 0)
135+
(mut _output nil)
136+
137+
(while (< _index (len _L)) {
138+
(if (or (nil? _output) (< (@ _L _index) _output))
139+
(set _output (@ _L _index)))
140+
(set _index (+ 1 _index)) })
141+
_output }))
142+
143+
# @brief Find the maximum in a list of numbers
144+
# @param _L list of numbers
145+
# @details The original list is not modified.
146+
# =begin
147+
# (let value (list:min [0 1 2 3 5 8])) # 8
148+
# =end
149+
# @author https://github.com/SuperFola
150+
(let max (fun (_L) {
151+
(mut _index 0)
152+
(mut _output nil)
153+
154+
(while (< _index (len _L)) {
155+
(if (or (nil? _output) (> (@ _L _index) _output))
156+
(set _output (@ _L _index)))
157+
(set _index (+ 1 _index)) })
158+
_output }))
159+
118160
(import std.Math :min :max)
119161

120162
# @brief Drop the first n elements of a list
121163
# @param _L the list to work on
122164
# @param _n the number of elements to drop
123-
# @details The original list is left unmodified.
165+
# @details The original list is not modified.
124166
# =begin
125167
# (let cool-stuff [1 2 3 4 5 6 7 8 9])
126168
# (print (drop cool-stuff 4)) # [5 6 7 8 9]
@@ -143,7 +185,7 @@
143185
# @brief Drop the first elements of a list, while they match a given predicate
144186
# @param _L the list to work on
145187
# @param _f the predicate
146-
# @details The original list is left unmodified.
188+
# @details The original list is not modified.
147189
# =begin
148190
# (let cool-stuff [1 2 3 4 5 6 7 8 9])
149191
# (print (dropWhile cool-stuff (fun (a) (< a 4)))) # [4 5 6 7 8 9]
@@ -164,7 +206,7 @@
164206
# @brief Keep elements in a given list if they follow a predicate
165207
# @param _L the list to work on
166208
# @param _f the predicate
167-
# @details The original list is left unmodified.
209+
# @details The original list is not modified.
168210
# =begin
169211
# (import std.Math)
170212
# (print (filter [1 2 3 4 5 6 7 8 9] math:even)) # [2 4 6 8]
@@ -182,7 +224,7 @@
182224
# @brief Apply a given function to each element of a list
183225
# @param _L the list to work on
184226
# @param _f the function to apply to each element
185-
# @details The original list is left unmodified.
227+
# @details The original list is not modified.
186228
# =begin
187229
# (print (map [1 2 3 4 5 6 7 8 9] (fun (e) (* e e)))) # [1 4 9 25 36 49 64 81]
188230
# =end
@@ -199,7 +241,7 @@
199241
# @brief Apply a function to the elements of a list to reduce it
200242
# @param _L the list to work on
201243
# @param _f the function to apply
202-
# @details The original list is left unmodified.
244+
# @details The original list is not modified.
203245
# =begin
204246
# (let cool [1 2 3 4 5 6 7 8 9])
205247
# (print (reduce cool (fun (a b) (+ a b)))) # 45
@@ -216,7 +258,7 @@
216258

217259
# @brief Flatten a list
218260
# @param _L the list to work on
219-
# @details The original list is left unmodified.
261+
# @details The original list is not modified.
220262
# =begin
221263
# (let cool [[1 2 3] [4] 5 6 [7 8] 9])
222264
# (print (flatten cool)) # [1 2 3 4 5 6 7 8 9]
@@ -238,7 +280,7 @@
238280
# @brief Apply a given function to each element of a list and then flatten it
239281
# @param _L the list to work on
240282
# @param _f the function to apply to each element
241-
# @details The original list is left unmodified.
283+
# @details The original list is not modified.
242284
# =begin
243285
# (let cool [1 2 3 4])
244286
# (print (flatMap cool (fun (a) [a a]))) # [1 1 2 2 3 3 4 4]
@@ -260,7 +302,7 @@
260302
# @brief Take the first n elements of
261303
# @param _L the list to work on
262304
# @param _n the number of elements to take
263-
# @details The original list is left unmodified.
305+
# @details The original list is not modified.
264306
# =begin
265307
# (print (take [1 2 3 4 5 6 7 8 9] 4)) # [1 2 3 4]
266308
# =end
@@ -278,7 +320,7 @@
278320
# @brief Take the first n elements of a list, given a predicate
279321
# @param _L the list to work on
280322
# @param _f the predicate
281-
# @details The original list is left unmodified.
323+
# @details The original list is not modified.
282324
# =begin
283325
# (print (takeWhile [1 2 3 4 5 6 7 8 9 10] (fun (a) (< a 4)))) # [1 2 3]
284326
# =end
@@ -299,7 +341,7 @@
299341
# @brief Partition a list in two, given a predicate
300342
# @param _L the list to work on
301343
# @param _f the predicate, accepting the value and its index
302-
# @details The original list is left unmodified.
344+
# @details The original list is not modified.
303345
# =begin
304346
# (let a [1 2 3])
305347
# (print (list:partition a (fun (c i) (= 0 (mod c 2))))) # [[2] [1 3]]
@@ -321,7 +363,7 @@
321363

322364
# @brief Unzip a list of [[a b] [c d]...] into [[a c ...] [b d ...]]
323365
# @param _L the list to work on
324-
# @details The original list is left unmodified.
366+
# @details The original list is not modified.
325367
# =begin
326368
# (let zipped [[1 5] [2 6] [3 7] [4 8]])
327369
# (print (unzip zipped)) # [[1 2 3 4] [5 6 7 8]]
@@ -343,7 +385,7 @@
343385
# @brief Zip two lists into one: [1 2 3 4] and [5 6 7 8] will give [[1 5] [2 6] [3 7] [4 8]]
344386
# @param _a the first list to work on
345387
# @param _b the second list to work on
346-
# @details The original lists are left unmodified.
388+
# @details The original lists are not modified.
347389
# =begin
348390
# (let a [1 2 3 4])
349391
# (let b [5 6 7 8])
@@ -362,7 +404,7 @@
362404

363405
# @brief Zip a list elements with their index. [5 6 7 8] will give [[0 5] [1 6] [2 7] [3 8]]
364406
# @param _L the list to iterate over
365-
# @details The original list is left unmodified.
407+
# @details The original list is not modified.
366408
# =begin
367409
# (let a [5 6 7 8])
368410
# (print (zipWithIndex a)) # [[0 5] [1 6] [2 7] [3 8]]
@@ -381,7 +423,7 @@
381423
# @param _L the list to work on
382424
# @param _init an init value
383425
# @param _f a function to apply to the list
384-
# @details The original list is left unmodified.
426+
# @details The original list is not modified.
385427
# =begin
386428
# (let a [1 2 3 4])
387429
# (print (foldLeft a 0 (fun (a b) (+ a b)))) # 10
@@ -512,7 +554,7 @@
512554
_output }))
513555

514556
# @brief Insert an element (or expand a list) at a given position inside a list
515-
# @details Original list is left unmodified
557+
# @details The original list is not modified
516558
# @param _L list to insert element(s) in
517559
# @param _index where to insert
518560
# @param _value value to insert

tests/functional-tests.ark

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,47 @@
11
(import std.Functional:*)
22
(import std.Testing)
3+
(import std.List)
34

45
(let foo (fun (x) (+ x 3)))
56
(let egg (fun (y) (* y 2)))
67
(let bar (fun (x y) (- x y)))
78

89
(test:suite functional {
9-
(test:eq ((compose foo egg) 5) (foo (egg 5)))
10-
(test:eq ((compose egg egg) 5) (egg (egg 5)))
11-
# no need to test left and right because they were already tested by the exceptions tests (throw, return)
12-
(test:eq ((flip bar 5) 6) (bar 6 5))
13-
(test:eq ((flip bar 6) 5) (bar 5 6))})
10+
(test:case "compose" {
11+
(test:eq ((compose foo egg) 5) (foo (egg 5)))
12+
(test:eq ((compose egg egg) 5) (egg (egg 5))) })
13+
14+
(test:case "left & right" {
15+
(let err (left 5))
16+
(err
17+
(fun (x) (test:expect true))
18+
(fun (x) (test:expect false)))
19+
20+
(let ok (right 6))
21+
(ok
22+
(fun (x) (test:expect false))
23+
(fun (x) (test:expect true))) })
24+
25+
(test:case "flip" {
26+
(test:eq ((flip bar) 5 6) (bar 6 5))
27+
(test:eq ((flip bar) 6 5) (bar 5 6)) })
28+
29+
(test:case "identity" {
30+
(test:eq (identity nil) nil)
31+
(test:eq (identity []) [])
32+
(test:eq (identity "hello") "hello") })
33+
34+
(test:case "recombine" {
35+
(let mean (recombine
36+
(fun (a b) (/ a b))
37+
list:sum
38+
list:size))
39+
(test:eq (mean [0 1 1 2 3 5 8 13]) 4.125)
40+
(test:eq (mean [0]) 0)
41+
42+
(let minMax (recombine
43+
(fun (a b) [a b])
44+
list:min
45+
list:max))
46+
(test:eq (minMax [1 1 2 3 5 8 13]) [1 13]) })})
47+

tests/list-tests.ark

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222

2323
(test:eq (builtin__list:setAt a 0 5) (list:setAt a 0 5))
2424

25+
(test:eq (list:size []) 0)
26+
(test:eq (list:size [1 2 3]) 3)
27+
2528
(list:forEach a (fun (e) {
2629
# just assert we have something, basically it's just a while + @
2730
(test:neq e nil)}))
@@ -32,6 +35,14 @@
3235
(test:eq (list:sum b) (+ 4 5 6))
3336
(test:eq (list:sum []) 0)
3437

38+
(test:eq (list:min []) nil)
39+
(test:eq (list:min b) 4)
40+
(test:eq (list:min [-1]) -1)
41+
42+
(test:eq (list:max []) nil)
43+
(test:eq (list:max b) 6)
44+
(test:eq (list:max [-1]) -1)
45+
3546
(test:eq (list:drop a 0) [1 2 3])
3647
(test:eq (list:drop a 1) [2 3])
3748
(test:eq (list:drop a 2) [3])

0 commit comments

Comments
 (0)