@noelwelsh
There are a few things I'd like to pick at here but are probably not worth getting into - I would nitpick that "direct-style" doesn't have multiple definitions (whether it has one is up for debate, but certainly not more than one), but that there are multiple ways of achieving it, for example. But it's not all that interesting.
I'll try to (heavily) rephrase your point to make sure I get it - and if I do, I think you've hit the nail on the head and there's a longer, quite interesting discussion to be had.
Monadic style forces a very strong separation between operations ("effectful computations") and values (everything else). You cannot possibly find yourself running an operation without meaning to, because that's a compile error. For example:
```
val line: IO[String] = ???
line ++ line
```
The compiler forces you to make it very clear whether you want to run `line` once or twice here.
Direct style weakens that separation. It still exists, but running a computation when you don't mean to is no longer a compile error.
For example (using capabilities because I need to use something):
```
val line: Tty ?=> String = ???
line ++ line
```
The compiler understands this to mean you want to run `line` twice.
This is quite related to my point on RT. In the direct-style version, `line` is not RT, and you, as a developer, need to keep track of that.
Ox doesn't give you this information at the type level.
Capabilities do, but they also make no syntactic difference between running an operation or reading a value. Better, but not great.
Some languages have a clear syntax for running an operation. Eff, for example, has you go `perform YourOperation`.
There's a fairly large design space, and not all languages are equal. But I think that in Eff for example, you lose the RT aspect, and it doesn't really matter for the properties we care about (ease of reasoning in particular).