aboutsummaryrefslogtreecommitdiff
path: root/p99/p07.neb
diff options
context:
space:
mode:
Diffstat (limited to 'p99/p07.neb')
-rw-r--r--p99/p07.neb57
1 files changed, 57 insertions, 0 deletions
diff --git a/p99/p07.neb b/p99/p07.neb
new file mode 100644
index 0000000..9eee9ef
--- /dev/null
+++ b/p99/p07.neb
@@ -0,0 +1,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)))