I/O is not the only thing monads are useful for, far from it. Having the concept of a monad lets you write generic code that will operate on any monad (just as e.g. having the concept of a collection lets you write generic code that will operate on any collection, or indeed having the concept of a number lets you write generic code that will work for any number rather than having to write your program as a big lookup table with explicit cases for every number).
Generic operations on monads are great, but you need code written in terms of monad operations to take advantage of them. Monadic code in Swift has a few problems.
1. There's no do-notation in Swift. Your code will be littered with weird operators that make it (at least slightly) harder to read.
2. It's less efficient. The runtime system has to create and destroy additional closures, increment and decrement additional reference counts, and so on.
3. It's difficult to interface with procedural code, since your monadic code must be pure.
So when do you write monadic code versus procedural code? In practice, the monadic parts of your code will end up associated with particular tasks that lend themselves to the monadic style. But why not then specialize this code to its particular task? In the Treelog example, using specific Treelog terminology instead of generic monad operators would make the code easier to read and understand.
When you have specialized code you use the specific terminology - just as when you have code that works only with a list, you'll use list terminology rather than generic collection terminology. You use the monadic parts when you need to abstract over it, just like with generics.
E.g. I have three client reports that share a common superclass but have different requirements. One of them needs some extra aggregated statistics (Writer, similar to treelog). One of them needs us to make an async call to their system for each row (Future). One of them needs some data from redis. But the superclass logic of "read a bunch of rows from our database, combine the per-row results into a single report" is common. So the superclass uses the generic monad operations, and the subclasses have the specific implementations, and I don't have to copy/paste the same code for the three different reports.
Once you have a library of functions that work with any monad, custom monads are really easy to work with. So you can do things like http://typelevel.org/blog/2013/10/18/treelog.html or http://michaelxavier.net/posts/2014-04-27-Cool-Idea-Free-Mon... .