Iteratee¶
A resumable stream consumer that processes externally supplied input chunks and returns a result or a continuation requesting more input.
Core Idea¶
An iteratee is a stream consumer represented as a value that can be given more input, advance its computation, and return either a completed result or a continuation awaiting further input. A producer, often called an enumerator, supplies data chunks and an end-of-input indication. The consumer does not need to own or pull from the underlying file or socket; it describes how to process whatever arrives. Kiselyov's original design frames this as a separation between stream production and consumption.[1][2]
The consumer may be as simple as a whitespace counter or as intricate as a parser. Its crucial property is not a particular Haskell datatype spelling. Kiselyov's implementation uses done and continuation states with a message/error channel; a Stanford teaching implementation distinguishes Done, NeedInput, NeedIO, and Failed. These state labels differ, but both preserve externally fed, resumable consumption.[2][3] Stream transformers called enumeratees can be inserted between source and consumer; they are compositional partners rather than required parts of every individual iteratee.[1]
Structural Signature¶
Sig role-phrases:
- Externally supplied input — The consumer receives chunks or termination from a producer. Without an input-feeding boundary, an opaque loop that owns the source is not the iteratee interface.
- Resumable consumer state — A value carries partial progress and can suspend when more data are needed. A whole-list function that must be called only once lacks this interface.
- Input-driven step — Processing a chunk produces the next state or result. The step may consume all, some, or none of the current chunk.[2]
- Completion/continuation contract — The producer can learn whether to stop or provide more input; this is what permits early completion without blindly reading an entire source.[2]
- Residual and error discipline — Some variants return unconsumed bytes and expose failures or control messages. Exact constructors are implementation-specific, but a parser that stops mid-chunk must account for the suffix if later stages need it.[3]
What It Is Not¶
- Not an iterator synonym. A conventional iterator commonly exposes a next operation that the consumer pulls; here the producer feeds a resumable consumer value.
- Not the entire streaming pipeline. Enumerator and optional enumeratees surround the iteratee; the iteratee itself is the consumer role.[2]
- Not necessarily a fixed Continue/Done/Error algebra. Different libraries encode completion, effects, errors, and leftover data differently.[2][3]
- Not a constant-memory guarantee. A consumer can retain a growing partial line or buffer even when input is chunked.[1]
Scope of Application¶
Iteratees support incremental parsing, counting, filtering, and stream decoding when input should not be materialized all at once. Kiselyov demonstrates character counting, word parsing, filtered counting, and composition over file or communication sources.[1] The producer may bracket a file resource and close it when the consumer finishes early, but that behavior belongs to the source-management implementation, not to every iteratee by definition.[1]
An iteratee can run over a finite file, a network stream, or an in-memory sequence. It need not be distributed, event-time-aware, or asynchronous. The actual memory and latency behavior depends on chunk size, held state, producer policy, and how terminal and error conditions are propagated.
Clarity¶
Separate three roles: source produces input, Iteratee consumes and resumes, and optional enumeratee transforms an outer stream into an inner one. In Kiselyov's file example, enum_file opens, feeds, and closes the file; the whitespace-count iteratee can be run without knowing whether characters came from a file or another producer.[1] This separation is what supports predictable resource lifetime in that implementation. Saying “the iteratee opens and closes the file” would invert the roles.
Manages Complexity¶
The consumer exposes just enough state for a producer to know whether further input is needed. A line parser can stop at a delimiter and return its residual bytes; a file producer can stop reading after a satisfied consumer. Stream transformers can decode or filter incrementally without constructing the full intermediate sequence.[1][3] This modularity reduces coupling between parsing logic and I/O policy. It also creates obligations: a producer must respect completion, a parser must not lose unconsumed input, and an allegedly streaming consumer must not accumulate an unbounded result by accident.
Abstract Reasoning¶
Think of the iteratee state \(I\) and a supplied chunk \(c\) as a transition \(step(I,c) \to I'\) or \(Done(r,rest)\) in a particular implementation. If \(I'\) requests more, the producer feeds another chunk; if it is done, production can stop. In the Stanford line-reader, a chunk is split at the first newline, and the suffix becomes the residual chunk rather than disappearing.[3] In Kiselyov's implementation, a stream transform such as character-to-word conversion forms an inner stream whose consumer still follows this incremental logic.[1] The algebra of exact constructors is variable; the compositional consumer behavior is stable.
Knowledge Transfer¶
When evaluating an unfamiliar stream library, locate the resumable consumer, producer, step response, termination signal, and residual/error path rather than searching for the literal type name Iteratee. Ask whether early completion stops the source and closes resources, and whether a mid-chunk stop preserves data for the next consumer. These questions transfer across libraries, whereas Haskell type constructors, monad combinators, and scheduling choices do not.[2][3]
Examples¶
File-backed whitespace count¶
Kiselyov's countWS iteratee updates a count as characters arrive. enum_file feeds it character chunks, closes the file when exhausted or when the iteratee has stopped requesting data, and a runner extracts the count. The iteratee itself need not hold a file handle.[1]
Mapped back: Externally supplied input → characters from enum_file; Resumable consumer state → current count and willingness to receive more; Input-driven step → test each character for whitespace; Completion/continuation contract → continue until terminal signal, then return count; Residual/error discipline → not exercised by this count-to-EOF example. Separately, enum_file owns file opening and closure in this implementation.
Read a line without losing the next one¶
The Stanford teaching iteratee receives a byte chunk containing a newline followed by additional bytes. Its readLine logic returns the completed line with a residual chunk holding the suffix; a later consumer can process that suffix instead of rereading the source.[3]
Mapped back: Externally supplied input → byte chunk; Resumable consumer state → accumulated prefix while no newline is present; Input-driven step → split at the delimiter; Completion/continuation contract → Done once the line exists, NeedInput otherwise; Residual/error discipline → suffix returned in Done rather than discarded.
Structural Tensions¶
- Early completion versus input preservation. A consumer should stop once its result is known, but the latest producer chunk may contain bytes after the stopping point. Without residual handling, sequential parsing loses those bytes. Diagnostic: Where is the unconsumed suffix recorded when Done occurs mid-chunk?[3]
- Incremental feeding versus bounded state. Small chunks avoid whole-stream materialization, yet a consumer waiting for an unbounded delimiter or retaining every element can still grow without limit. Diagnostic: What bounds the chunk and consumer's accumulated state under the expected inputs?[1]
Structural–Framed Character¶
Iteratee is mixed-framed: an externally fed resumable consumer has an operational contract, but its interface and effect handling are designed within programming practice. Its evaluative weight is conditional; it may make incremental input and resource control easier, yet a particular library can still be awkward or incorrect. It is human-practice-bound because producers, consumer states and resumption protocols are software artifacts. Its institutional origin is functional-programming design across several libraries, not one canonical constructor set or standards authority. Its vocabulary travel reaches file, network and other chunked sources when the same consumer-fed/resume contract is preserved; Haskell-specific type constructors do not travel by themselves. Import versus recognition asks whether the consumer explicitly requests more input, can resume, and reports completion, not whether code uses names like Continue or merely processes a stream.
The portable skeleton might be incremental resumption of a consumer under externally supplied input, an explicit future-prime candidate rather than an asserted live parent. Live Iteration describes repeated steps but not this interface; live Stream Processing adds event-time/watermark commitments absent from a finite-file iteratee. Its character: a designed incremental-consumption interface whose producer/consumer roles recur in computing while its exact contract remains programming-specific.
Structural Core vs. Domain Accent¶
The prime-bar issue is not whether “incremental processing” is useful, but what makes this particular interface an iteratee.
What is skeletal. A consumer can hold state, receive bounded input from an external producer, and either continue or report that it is done. That resumable-consumer relation is a future-prime candidate requiring separate cross-domain testing; no live strict genus has been asserted. Iteration captures repetition but not external feeding or explicit completion semantics.
What is domain-bound. The consumer participates in a programming interface whose step result lets a producer decide whether to supply another chunk, stop or handle an error. Remove resumability and explicit consumer/producer control and an eager parse over a whole file is not an iteratee. Haskell monads, enumerators, enumeratees, precise constructor names, effect types and chunk encodings vary across implementations. Resource bracketing and residual data are important design concerns, but no one representation of them is universally constitutive. A finite file is a legitimate setting; event-time watermarks are not required.
Why this is not a prime. A generic resumable process may be broadly useful, but its independent prime identity is unproven here. Iteratee is literally recognized in software systems with this incremental consumer protocol. Calling a human reading a report in installments an “iteratee” imports the analogy without executable producer/consumer state transitions. The current draft properly stays unparented rather than borrowing the extra semantics of Stream Processing or Pipeline.
Instantiates / Related Primes¶
No strict typed parent relation is asserted in the current DAG.
Neighborhood in Abstraction Space¶
Iteratee sits in a sparse region of the domain-specific corpus (77th percentile for distinctiveness): few abstractions share its structure, so a faithful description tends to retrieve it precisely.
Family — Program Execution & Runtime Concepts (27 abstractions)
Nearest neighbors
- Stream Abstract Data Type — 0.86
- Rematerialization — 0.83
- Dynamic Problem — 0.82
- Automation — 0.82
- Automaton — 0.82
Computed from structural-signature embeddings · 2026-10-08
Not to Be Confused With¶
A whole-list fold can produce the same numerical answer as an iteratee yet lacks an exposed resumable consumer interface if it demands the entire list up front. An iterator that owns a source handle and is repeatedly polled reverses the direction of control. An enumeratee is a transformer between streams, not the terminal consumer itself, although an implementation may use the iteratee type internally for its outer-input side.[2]
References¶
[1] Oleg Kiselyov, “Iteratees”, research manuscript, §§2–3. Author-hosted PDF directly checked for the countWS/enum_file example, producer-managed file lifetime, enumeratee transformations, and incremental processing. registry ↩a ↩b ↩c ↩d ↩e ↩f ↩g ↩h ↩i ↩j
[2] Oleg Kiselyov, “Iteratees: Incremental multi-level input processing and collection enumeration”, project documentation, “The design of iteratees.” Original author's page directly checked for the state, stream, enumerator, and enumeratee definitions. registry ↩a ↩b ↩c ↩d ↩e ↩f ↩g ↩h
[3] Stanford University CS240H, “The iteratee abstraction”, lecture slides (2016), sections “Representing iteratees,” “Example: Reading a line of input,” and “Enumerators.” Directly checked for a distinct state algebra and residual-chunk example. registry ↩a ↩b ↩c ↩d ↩e ↩f ↩g ↩h