This is how Haskell's Textand ByteString work when you use their Builder interfaces. They allocate an initial memory buffer and transform all Text/ByteString operations to sequences of buffer operations. When the buffer fills they flush it with a memcpy. The advantage of that approach is that it is not tied to a particular application.

SelectMany basically gives you bind and chaining from statements in LINQ gives you something like do syntax - so yeah, you can get closer to sane monads then you can in say, java, but I wouldn't call c#'s syntax for working with monads "nice" so much as "a happy accident" and "strange."

If you want to see syntax that makes working with monads nice, go look at f#.

I can't say I disagree. F# and Haskell's syntaxes are better designed for the general case, whereas C#'s is a bit... look like SQL.

However, when comparing queries with multiple named variables against what they get translated into (with slightly larger anonymous types at each step) just in C#, they really are nicer. That's all I meant to imply.

Yes, they pulled in some functional people when designing Linq. But they did not set out to and did not prioritize a generalized monad syntax for C#. They prioritized making it "look like SQL" and making it render expression trees so that they could apply transformations later when they needed to for cases like DLINQ. What drove Linq is pretty clearly the need for a new/better data access story. The rest was gravy. Don't get me wrong, there's a lot of gravy there, but the syntax choices and compromises make the design philosophy and primary intent pretty clear.

Also, from the comment that you linked:

You can actually use query comprehension with any monad, as my colleague Wes describes here, but doing so looks pretty weird and I recommend against it in production code.

To be fair, Haskell doesn't have even allow arbitrary monads in its list comprehensions. On the other hand, a lot of monads (including parser combinators in the OP) do fit the LINQ model pretty much perfectly.

To be fair, Haskell doesn't have even allow arbitrary monads in its list comprehensions.

Well, yeah, but this is more drawing a comparison to general monad syntax (do form or even the bind operator.)

On the other hand, a lot of monads (including parser combinators in the OP) do fit the LINQ model pretty much perfectly.

Eh. They work, but they don't really fit or make much sense syntactically. E.g. in the case of parser combinators, SelectMany has nothing to do with "selecting many" and the meanings of from and select don't make as much sense as the more general assignment/let and return. (Maybe they do or could, but other functional languages are fairly consistent with this.)

They had a chance to use general monad keywords and they chose to instead use vocabulary specific to the sequence monad, because their end goal was not "provide monad support in c#/vb.net" so much as "provide language-integrated querying in c#/vb.net." It all works the same, it just smells funny.

Parser combinators describe things at such a high level that we can easily optimize them and, suddenly, making a super-efficient parser is as easy as applying an attribute and being careful about the order of your fields. Plus, if you get things wrong, it doesn't all blow up in your face: the optimization is simply not applied. (Well.. depending on the application that might count as blowing up in your face, but at least it doesn't give wrong results or scribble over random bits of memory.)

Zero copy with networking is possible and done. If you use raw sockets you can do this as long as you keep up with the incoming stream. But ethernet is slow and caching this kind of thing to a ram disc is zero copy if you do it right. But you are paying the cost of reassembly already and the driver internals must do some copies anyway so if you take the raw socket output and put it in a buffer directly you have still saved some copies.

I'm really impressed by the weird way his parsers work, there's no data yet when he combines them, then he injects it sort of externally, like, for x in intParser doesn't mean anything by itself, the magic happens in the corresponding Select/SelectMany. I was pretty sure that it couldn't possibly work because you might need to use bound variables before you can stick the data where you want, similar to what is described here, and yet it does!

Yeah, what's weird and what I somehow forgot to mention is that this magic is delayed until the result is actually needed. If you read the thing I linked to, you'll see how it's sort of unexpected; if I'd not seen it with my own eyes I'd have said that you can't do that with monads, they are too restrictive, you need applicative functors for that. And would be wrong!