git.iko.soy/rowtype-yoga/purescript-yoga-om-strom
on main help sign in
346 lines 8.1 kB history raw
1# Strom Quick Reference
3One-page reference for the Strom API.
5## Type Signature
7```purescript
8newtype Strom ctx err a
9```
11A stream that:
12- Emits values of type `a`
13- May fail with errors in `err`
14- Requires context `ctx`
15- Performs effects in Om
17## Construction
19```purescript
20empty -- Empty stream
21succeed a -- Single element
22fail err -- Immediate failure
24fromArray [1, 2, 3] -- From array
25fromFoldable list -- From any Foldable
26fromOm omEffect -- From Om effect
27fromAff affEffect -- From Aff effect
29range 1 100 -- Integers [1..100)
30iterate (+ 1) 0 -- 0, 1, 2, 3, ...
31repeat "x" -- "x", "x", "x", ...
32repeatOm fetchData -- Repeat effect
34unfold f seed -- Pure unfold
35unfoldOm f seed -- Effectful unfold
36```
38## Running (Consuming)
40```purescript
41runCollect stream -- Om ctx err (Array a)
42runDrain stream -- Om ctx err Unit
43runFold init f stream -- Om ctx err b
44traverse_ handler stream -- Om ctx err Unit
45subscribe handler stream -- Om ctx err (Om ctx err Unit)
46```
48## Transformations
50```purescript
51stream # map f -- Pure map
52stream # mapM f -- Effectful map
53stream # mapParallel 5 f -- Parallel (max 5)
54stream >>= toStream -- Monadic bind (flatten)
55stream # scan f init -- Running fold
56stream # mapAccum f state -- Stateful map
57stream # tap observer -- Pure observe
58stream # tapM observer -- Effectful observe
59```
61## Selection
63```purescript
64stream # take 10 -- First 10
65stream # takeWhile predicate -- While true
66stream # takeUntil predicate -- Until true (inclusive)
68stream # drop 5 -- Skip first 5
69stream # dropWhile predicate -- Skip while true
71stream # filter predicate -- Pure filter
72stream # filterM predicate -- Effectful filter
73stream # collect partialFn -- Filter + map
74stream # collectM partialFn -- Effectful collect
76stream # changes -- Remove consecutive dups
77```
79## Combining
81```purescript
82s1 `append` s2 -- Sequential concat
83s1 <> s2 -- Same (Semigroup)
84concat [s1, s2, s3] -- Multiple streams
86s1 `merge` s2 -- Non-deterministic
87zip s1 s2 -- Tuple pairs
88zipWith f s1 s2 -- Zip with function
89interleave s1 s2 -- Deterministic alternating
91race [s1, s2, s3] -- First to emit
92```
94## Grouping
96```purescript
97stream # grouped 10 -- Chunks of 10
98stream # chunked 50 -- Batches of 50
99partition predicate stream -- Split in two
100```
102## Error Handling
104```purescript
105stream # catchAll handler -- Catch and recover
106s1 `orElse` s2 -- Alternative on fail
107s1 <|> s2 -- Same (Alt)
108```
110## Common Patterns
112### API Pipeline
113```purescript
114Strom.range 1 1000
115 # Strom.mapParallel 10 fetchUser
116 # Strom.filter (_.active)
117 # Strom.grouped 50
118 # Strom.traverse_ saveBatch
119```
121### Pagination
122```purescript
123Strom.unfoldOm fetchPage token
124 >>= Strom.fromArray
125 # Strom.runCollect
126```
128### Event Processing
129```purescript
130events
131 # Strom.filter isValid
132 # Strom.changes
133 # Strom.mapM enrichEvent
134 # Strom.grouped 100
135 # Strom.traverse_ processBatch
136```
138### Fibonacci
139```purescript
140Strom.unfold
141 (\(Tuple a b) -> Just (Tuple a (Tuple b (a + b))))
142 (Tuple 0 1)
143 # Strom.take 20
144```
146### Running Total
147```purescript
148numbers
149 # Strom.scan (+) 0
150 # Strom.runCollect
151```
153### Indexed Items
154```purescript
155items
156 # Strom.mapAccum
157 (\i x -> Tuple (i + 1) { index: i, item: x })
158 0
159```
161### With Cancellation
162```purescript
163cancel <- Strom.subscribe handler stream
164-- later:
165cancel
166```
168## Type Classes
170Strom is a:
171- `Functor` - use `map`
172- `Apply` / `Applicative` - use `pure` / `<*>`
173- `Bind` / `Monad` - use `>>=` / do-notation
174- `Semigroup` / `Monoid` - use `<>` / `mempty`
175- `Alt` / `Plus` / `Alternative` - use `<|>` / `empty`
177## Tips
179### Compose with `#`
180```purescript
181result <- stream
182 # Strom.filter predicate
183 # Strom.map transform
184 # Strom.grouped 10
185 # Strom.runCollect
186```
188### Parallel Processing
189```purescript
190-- Sequential (slow)
191stream # Strom.mapM fetchData
193-- Parallel (fast!)
194stream # Strom.mapParallel 10 fetchData
195```
197### Infinite Streams
198Always use `take` or `takeWhile` before running!
199```purescript
200Strom.iterate (+ 1) 0
201 # Strom.take 100 -- ← Important!
202 # Strom.runCollect
203```
205### Memory Efficiency
206Use `runDrain` or `traverse_` instead of `runCollect` for large streams:
207```purescript
208-- ❌ Loads everything into memory
209results <- stream # Strom.runCollect
211-- ✅ Processes incrementally
212stream # Strom.traverse_ processOne
213```
215### Batching
216Group items for efficient bulk operations:
217```purescript
218items
219 # Strom.grouped 100
220 # Strom.traverse_ bulkInsert
221```
223### Context Access
224Use Om's `ask` in effectful operations:
225```purescript
226stream
227 # Strom.mapM (\item -> do
228 ctx <- Om.ask -- Access context
229 processWithContext ctx item
230 )
231```
233## Performance
235- **Chunked**: Processes ~1000 elements at a time internally
236- **Lazy**: Values computed only when pulled
237- **Backpressure**: Consumer controls pace
238- **Parallel**: `mapParallel n` runs up to `n` concurrent effects
240## When to Use Strom
242✅ **Use Strom for**:
243- Data processing pipelines
244- API integrations
245- Batch operations
246- File I/O
247- Event streams
248- Large datasets
249- Paginated APIs
251❌ **Don't use for**:
252- Small collections (use Array)
253- UI events (use Bolson Events)
254- Simple transformations (use Array.map)
256## Comparison
258| Need | Array | Bolson Event | Strom |
259|------|-------|--------------|-------|
260| Small collection | ✅ | ❌ | ❌ |
261| Large dataset | ❌ | ❌ | ✅ |
262| UI events | ❌ | ✅ | ❌ |
263| API pipeline | ❌ | ❌ | ✅ |
264| Backpressure | ❌ | ❌ | ✅ |
265| Parallel processing | ⚠️ | ❌ | ✅ |
267## Common Gotchas
269### 1. Infinite Streams
270```purescript
271-- ❌ Never finishes!
272Strom.repeat 42 # Strom.runCollect
274-- ✅ Bounded
275Strom.repeat 42 # Strom.take 10 # Strom.runCollect
276```
278### 2. Effects in `map`
279```purescript
280-- ❌ Effects won't run!
281stream # Strom.map (\x -> Om.fromAff $ log x)
283-- ✅ Use mapM
284stream # Strom.mapM (\x -> Om.fromAff $ log x)
285```
287### 3. Forgetting to Run
288```purescript
289-- ❌ Just a value, doesn't run!
290let result = stream # Strom.map (+ 1)
292-- ✅ Actually execute it
293result <- stream
294 # Strom.map (+ 1)
295 # Strom.runCollect
296```
298## Full Example
300```purescript
301module Main where
303import Prelude
304import Effect.Aff (Aff, launchAff_)
305import Effect.Class.Console as Console
306import Yoga.Om as Om
307import Yoga.Om.Strom as Strom
309type Context = { apiKey :: String }
311main :: Aff Unit
312main = launchAff_ $ Om.runOm context handlers program
313 where
314 context = { apiKey: "secret" }
315 handlers = { exception: \err -> Console.log (show err) }
317program :: Om Context () Unit
318program = do
319 results <- Strom.range 1 100
320 # Strom.filter (\n -> n `mod` 2 == 0)
321 # Strom.mapParallel 5 (\n -> do
322 { apiKey } <- Om.ask
323 -- Use apiKey to fetch data
324 pure (n * 2)
325 )
326 # Strom.grouped 10
327 # Strom.tapM (\batch ->
328 Om.fromAff $ Console.log $ "Processing batch of " <> show (Array.length batch)
329 )
330 >>= Strom.fromArray
331 # Strom.runCollect
333 Om.fromAff $ Console.log $ "Final results: " <> show results
334```
336## Documentation
338- **README.md** - Comprehensive guide
339- **DEMO.md** - API showcase with examples
340- **COMPARISON.md** - vs ZIO ZStream
341- **SUMMARY.md** - What we built
342- **QUICKREF.md** - This file
344## Questions?
346Check the examples in `src/Yoga/Om/Strom/Examples.purs` - 18 comprehensive examples covering all use cases!