In OCaml

Streams flow smoothly in OCaml. With tail call optimization the argument against the stack based approach with a put style calls largely evaporates. With functions as first class values the code looks almost readable.

In this code type p (int -> unit) is the type of a routine that accepts an int and returns only as an invitation for further members of this stream. Identifiers whose spelling begins “sink” denote values of mode p; such values are the arcs that connect the nodes of the DAG—held by an upstream node and designating a downstream node. Routines whose name begins “make” take zero or more values of type p and return zero or more values of type p; every invocation of such a routine creates a new node.
endd is the dead sink (of type p) with no output.
makePr creates a node that prints and discard each value. It quits asking for more after a count established on creation.
makeId makes an identity node—no transformation.
makeTee is like the Unix tee shell command; it makes two identical streams from one.
makeIota makes a counter starting from some specified initial value.
sinkP is the dead end node; it swallows characters silently.
makeOdds makes nodes that omit every other element from the stream.
makeStut makes nodes that duplicate every stream element.
makeSep makes nodes that construct two streams, alternating characters going to alternate streams.
makeMerg makes nodes that merge two streams in the sense of the perfect shuffle. It returns two sinks and insists on getting its inputs alternately from the two sinks.
makeCmp makes a node that compares even and odd input characters and quits if they are unequal.
make2utf8 makes a node that converts Unicode code points into UTF-8.
makeFutf8 makes a node that converts back.
makePlist makes a node that originates a stream composed of the provide integer list, and then quits.

None invite additional characters until they cannot otherwise proceed. They are all deterministic; the language does not well support any other pattern.

Converting to UTF-8 is easy in a language where you can deposit consecutive characters as you compute them. Witness make2utf8. Converting from UTF-8 would be easy with a get next octet command, but otherwise the stack-coded-state must be represented with a couple of mutable variables. Witness makeFutf8.

The six statements at the end, each beginning “tr(fun” show six ways to plumb these nodes into a DAG and either print the output or test it.