aboutsummaryrefslogtreecommitdiff
path: root/p99/p07.neb
blob: 9eee9efd13371ca9689858ed88b8c5b6216016e4 (plain)
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
; P07 Flatten a nested array structure.
; Transform an array, possibly holding arrays as elements into a `flat'
; list by replacing each array with its elements (recursively).

(def a (list "a" (list "b" (list "c" "d") "e")))

; this belongs in stdlib
(func extend (lst1 lst2)
    (reduce append lst2 lst1))

; can overload functions of different arities
(func flatten-iter (item)
    (flatten-iter item (list)))

; iterative solution
(func flatten-iter (item acc)
    (branch
        ((eq? (typeof item) :[:any])
            (if (empty? item)
                    acc
                (flatten-iter (rest item) (extend acc (flatten-iter (first item))))))
        (#true
            (append acc item))))

; we can also use the type system/dynamic dispatch to split up the work
(func flatten-typ (item)
    (flatten-typ item (list)))

; non-empty lists
(func flatten-typ (lst :{:any} acc)
    (flatten-typ (rest lst) (extend acc (flatten-typ (first lst)))))

; empty lists
(func flatten-typ (lst :nil acc)
    acc)

; other things
; note: we would need to know what type(s) is inside the list to avoid an
; ambiguous definition
;(func flatten-typ (item :string acc)
;    (append acc item))

; this might be clearer/more flexible
; maybe "not this type" should be a thing, like :![:any]
(func not-a-list? (item)
    (not (eq? (typeof item) :[:any])))

(type :not-a-list :any not-a-list?) ; should be able to pass a lambda

; this handles anything that's not a list
(func flatten-typ (item :not-a-list acc)
    (append acc item))

(print (->string a))
(print (->string (flatten-iter a)))
(print (->string a))
(print (->string (flatten-typ a)))