(xml-read stdin) -> reads XML nodes from stdin
(xml-read some-stream) -> reads XML nodes from some-stream
The differences between (readc stdin) and (stdin 'char) are small. One can be easily defined in terms of the other, so it's mostly a matter of what you want to extend.
Let's suppose you want to add a shiny new input type. Since input/output are just functions, this is easy enough to do:
(def my-stdin ()
...)
But now, let's say you wanted to have this function behave differently. There are two ways to do this: call the function with different parameters, or call a function that wraps around it, like readc.
I prefer the former because it avoids having a ton of tiny specialized functions like readc, peekc, etc. In other words, it's the idea of "where is this functionality encapsulated?" The functional approach is, "hey, let's make a function, that can then do stuff to different stuff" ala peekc, map, each, etc.
That's fine, and it's very extensible and generic in most circumstances. But in this particular case, reading or peeking a character are more specific. They only really make sense for streams, so it makes sense to encapsulate that functionality within streams, rather than making it a generic built-in function. Hence (stdin 'char) rather than (readc stdin).
This also makes it easier to special-case behavior for a particular stream. Consider the case where you want to change the behavior of stdin, but not change the behavior of other input streams. Piece of cake:
(extend stdin (x) (is x 'char)
...)
But if you try to extend `readc`, then now you end up with stuff like this:
(extend readc (x) (is x stdin)
...)
...but that won't work if somebody overwrites stdin. So now you need to store it in a let:
(let old stdin
(extend readc (x) (is x old)
...))
Basically, by passing arguments to the streams, I make it easier to extend an individual stream, but harder to extend all streams. Of course, I could still keep `readc` around, and have it defined to simply call (foo 'char), in which case we could get the best of both worlds: extending individual streams and extending globally (assuming code uses readc, rather than calling streams directly).
Oh, it also lets streams dynamically alter their behavior, without needing to extend global functions, and it makes it easier to define custom behavior for a stream, once again without needing to create more global functions, etc. etc.
I don't think it's a huge enough deal to fight over, though. As I said, the differences between the two approaches are small, and I could settle for either one. My gut says that passing arguments to streams to change their behavior is better, though. I could be wrong.