# Lazy Sequences `map`, `filter`, `take`, `drop`, and `mapcat` return **lazy sequences** when given a collection argument. The work isn't done until you consume the result. This lets pipelines over large or infinite inputs stay efficient. ## What Is Lazy? A lazy sequence computes its elements on demand. The chain below doesn't walk the whole input; it only computes what the terminal operation needs:
 @{ 1 2 3 4 5 6 7 8 9 10 }
    |> filter { ($it % 2) == 0 }
    |> map { $it * 10 }
    |> take 2
    |> collect
# => @{ 20 40 }
# only the first two even numbers were mapped 
The pipeline above terminates as soon as `take 2` has its two values. If the source were infinite, the pipeline would still complete. ## Operations That Return Lazy Seqs | Op | 1-arg (transducer) | 2-arg (lazy seq) | |---|---|---| | `map` | `[map f]` | `[map $xs f]` or `$xs \|> map f` | | `filter` | `[filter pred?]` | `[filter $xs pred?]` or `$xs \|> filter pred?` | | `take` | `[take n]` | `[take $xs n]` or `$xs \|> take n` | | `drop` | `[drop n]` | `[drop $xs n]` or `$xs \|> drop n` | | `mapcat` | `[mapcat f]` | `[mapcat $xs f]` or `$xs \|> mapcat f` | The 1-arg form returns a **transducer** (see [Transducers](transducers)). ## Realising Lazy Seqs Lazy seqs are not directly printable. Use a terminal operation to force them:
 set xs @{ 1 2 3 4 5 }

$xs |> map { $it * 2 } |> collect             # force to list
$xs |> filter even? |> count                  # count of matches
$xs |> map { $it * 2 } |> reduce 0 { $acc + $it }   # fold
$xs |> filter { $it > 2 } |> find { $it > 3 }  # first match
$xs |> map { $it * 2 } |> join ","            # stringify
$xs |> filter { $it > 2 } |> first            # same as `find` without pred
$xs |> filter { $it > 2 } |> last 
### TODO Implicit Realisation `for` loops, `echo`, and assignment (`set`) auto-realise a lazy seq:
 for x [map @{1 2 3} { $it * 2 }] { echo $x }    # realises via for-loop
echo $xs |> map { $it * 2 }                       # realises via echo
set result $xs |> map { $it * 2 }                 # realises on assignment 
## Pipelines vs Nested Calls Pipelines are the idiomatic form for multi-step transforms:
 # ✓ Preferred
@{ 1 2 3 } |> map { $it * 2 } |> filter { $it > 2 } |> collect

# ✗ Works, but unidiomatic
[filter [map @{ 1 2 3 } { $it * 2 }] { $it > 2 }] 
The pipeline form lets each step read left-to-right and avoids rightward drift. ## Step Fusion Pipeline steps fuse at runtime — the realisation walks the source once and runs every transform per element. No intermediate collections are allocated.
 @{ 1 2 3 4 5 }
    |> map { $it * 2 }
    |> map { $it + 1 }
    |> filter { $it > 4 }
    |> collect
# one walk, two maps and a filter per element 
## Caching Once a lazy seq element is forced, it's cached. Re-walking the same result doesn't re-run the pipeline:
 set xs [map @{ 1 2 3 } { expensive-op $it }]
echo [$xs first]                              # runs expensive-op on 1
echo [$xs first]                              # uses cached result 
## Postfix Sugar Pipeline operators are the most natural form, but single-step calls can also use postfix on a variable:
 set xs @{ 1 2 3 }
set doubled $xs(map { $it * 2 })
set evens  $xs(filter { ($it % 2) == 0 }) 
Note: there's **no space** between the variable and the opening paren. `$xs (map ...)` is a syntax error. ## Iteration Over Maps and Strings `ISeq` works on any sequence, not just lists. Maps yield `@{key value}` pairs; strings yield single chars:
 %{ :a 1 :b 2 } |> map { $it~1 } |> collect    # => @{ 1 2 }
"hello" |> map { $it(upper) } |> join ""      # => "HELLO" 
For more on this, see [Collections](collections). ## Early Termination With `take` `[take n]` is the primary tool for terminating an infinite or very large pipeline:
 def naturals [iterate { $it + 1 } 1]          # if you have iterate

# Without iterate, use range with a large bound and take what you need
[range 0 1000000] |> filter { ($it % 7) == 0 } |> take 5 |> collect
# => @{ 0 7 14 21 28 } 
## When To Use Transducers Instead The lazy-seq form is perfect for one-shot collection-to-collection transforms. Reach for transducers (see [Transducers](transducers)) when: - The same pipeline is applied to multiple collections. - The sink is something other than a vector (set, map, sum, custom reducer). - You want explicit early termination across the whole chain via `%Reduced`. ## Quick Reference | Op | Returns | Notes | |---|---|---| | `map` | Lazy seq (2-arg) | Apply f to each element | | `filter` | Lazy seq (2-arg) | Keep elements where pred truthy | | `take` | Lazy seq (2-arg) | First n elements | | `drop` | Lazy seq (2-arg) | All but first n elements | | `mapcat` | Lazy seq (2-arg) | Map then concatenate results | | `collect` | List | Force a lazy seq | | `reduce` | Folded value | Reduce with init and step fn | | `find` | First match or nil | Find first satisfying element | | `any?` / `all?` | Boolean | Existence / universality | | `group` | Map keyed by result | Partition by function | | `count` | Number | Length after realisation | | `first` / `last` | Element | Edges | | `sort` | List | Sorted copy | | `unique` | List | De-duplicated |