diff options
-rw-r--r-- | lib.c | 9 | ||||
-rw-r--r-- | tests/012/seq.tl | 58 | ||||
-rw-r--r-- | txr.1 | 33 |
3 files changed, 86 insertions, 14 deletions
@@ -3666,12 +3666,11 @@ static val lazy_flatten_scan(val list, val *escape) list = cdr(list); } else if (atom(a)) { return list; - } else do { + } else { push(cdr(list), escape); /* safe mutation: *escape is a local var */ list = a; a = car(list); - } while (consp(a)); - return list; + } } else if (*escape) { list = pop(escape); } else { @@ -3698,7 +3697,9 @@ static val lazy_flatten_func(val lcons) val lazy_flatten(val list) { - if (atom(list)) { + if (list == nil) { + return nil; + } if (atom(list)) { return cons(list, nil); } else { val escape = nil; diff --git a/tests/012/seq.tl b/tests/012/seq.tl index df5ce065..9aa61148 100644 --- a/tests/012/seq.tl +++ b/tests/012/seq.tl @@ -564,4 +564,60 @@ [separate-keys evenp (vec-list (range 1 20)) square] (#(4 16 36 64 100 144 196 256 324 400) #(1 9 25 49 81 121 169 225 289 361))) - +(mtest + (flatten '()) () + (flatten '(nil)) () + (flatten '(a)) (a) + (flatten '(a b)) (a b) + (flatten '(nil b)) (b) + (flatten '(a nil)) (a) + + (flatten '((nil))) () + (flatten '((a))) (a) + (flatten '((a) (b))) (a b) + (flatten '((nil) (b))) (b) + (flatten '((a) (nil))) (a) + + (flatten '((a b))) (a b) + (flatten '((nil b))) (b) + (flatten '((a nil))) (a) + + (flatten '(((())))) nil + (flatten '(((())) a)) (a) + (flatten '(((()) a))) (a) + (flatten '(((() a)))) (a) + (flatten '((((a))))) (a) + + (flatten 3) (3) + (flatten '(1 . 2)) :error + (flatten '(1 2 . 3)) :error + (flatten '(1 (2 . 3))) :error) + +(mtest + (flatten* '()) () + (flatten* '(nil)) () + (flatten* '(a)) (a) + (flatten* '(a b)) (a b) + (flatten* '(nil b)) (b) + (flatten* '(a nil)) (a) + + (flatten* '((nil))) () + (flatten* '((a))) (a) + (flatten* '((a) (b))) (a b) + (flatten* '((nil) (b))) (b) + (flatten* '((a) (nil))) (a) + + (flatten* '((a b))) (a b) + (flatten* '((nil b))) (b) + (flatten* '((a nil))) (a) + + (flatten* '(((())))) nil + (flatten* '(((())) a)) (a) + (flatten* '(((()) a))) (a) + (flatten* '(((() a)))) (a) + (flatten* '((((a))))) (a) + + (flatten* 3) (3) + (lforce (flatten* '(1 . 2))) :error + (lforce (flatten* '(1 2 . 3))) :error + (lforce (flatten* '(1 (2 . 3)))) :error) @@ -23103,27 +23103,40 @@ operation: no .coNP Functions @ flatten and @ flatten* .synb -.mets (flatten << list ) -.mets (flatten* << list ) +.mets (flatten >> { list | << atom }) +.mets (flatten* >> { list | << atom }) .syne .desc The .code flatten -function produces a list whose elements are all of the +function recursively traverses a nested +.metn list , +returning a list whose elements are all of the .cod2 non- nil -atoms contained in the structure of -.metn list . +atoms contained in +.metn list , +at any level of nesting. +If the argument is an +.meta atom +rather than a +.metn list , +then it is returned. +Otherwise, the +.meta list +argument must be a proper list, as must all lists +nested within it. The .code flatten* -function -works like -.code flatten +function calculates the same result as +.codn flatten , except that it produces a lazy list. It can be used to lazily flatten an -infinite lazy structure. +infinite lazy list. .TP* Examples: .verb + (flatten 42) -> 42 + (flatten '(1 2 () (3 4))) -> (1 2 3 4) ;; equivalent to previous, since @@ -23133,6 +23146,8 @@ infinite lazy structure. (flatten nil) -> nil (flatten '(((()) ()))) -> nil + + (flatten '(a (b . c))) -> ;; error .brev .coNP Functions @ flatcar and @ flatcar* |