Earlier quoted context omitted.
Monads themselves are composable via bind, but the values encapsulated by the monad are not. Consider there is no real converse to the return operator: once something has been wrapped by a monad, then it is forever stuck in that monadic world. That can be rather annoying, because in languages such as OCaml (not sure about Haskell &c), monad-like interfaces are a convenient abstraction, yet using them leads to highly…
Sure the values are. Any function `a -> b -> c` can be lifted into a function `m a -> m b -> m c` for any Monad. That's (part of) the exact thing that bind buys you. "Escaping" from a monad is an artifact of a bad intuition. There's no reason for a monad (m a) to "contain" values a and thus no reason to believe that they can be removed. Even Maybe is a sufficient model of this. I can make a whole big compositional pi…
What Color Is Your Function?
51–60 of 153 posts
Re: What Color Is Your Function?
#52Earlier quoted context omitted.
Except that's not an effect systems because you only have one real effect - the IO type. The challenge of effect systems is to describe effects and how they interact. For example, you'll have an effect that says "a lock is obtained" and one that says "a lock is released", and if you call them both, in the right order , in the same function, then that function has an effect of "mutating something under lock".
Sure it is! The effect `(MonadTeletype m, MonadNow m) => m a` is just as real as IO. There's nothing special about IO except that the Haskell RTS knows how to interpret it. I could, for instance, build a pure interpreter of those effects into, say, a stream transformer or compile it into a different language (though we'd have to do some tricks to expose Haskell's name binding). If you want your lock obtained/lock rel…
But that is what makes it an effect. Sure, you can model effects in a "hosted" language this way, but that's not what we mean by effects.
Re: What Color Is Your Function?
#53Earlier quoted context omitted.
Sure the values are. Any function `a -> b -> c` can be lifted into a function `m a -> m b -> m c` for any Monad. That's (part of) the exact thing that bind buys you. "Escaping" from a monad is an artifact of a bad intuition. There's no reason for a monad (m a) to "contain" values a and thus no reason to believe that they can be removed. Even Maybe is a sufficient model of this. I can make a whole big compositional pi…
Let's take a simple, quotidian example: logging and errors. I write functions that produce logs and may generate errors. If I were using monads, I'd have a log monad and an error monad. For logs, my functions would produce a value and a list of log messages. The monad would combine the list of messages. For errors, my functions return an OK and a value, or an error, and the monad short-circuits errors. Now I write fu…
If you don't mind deferring the definition of "correct" to the interpreter writer then that intentional choice is captured by
(MonadWriter Log m, MonadExcept m) => m a
If you want more controls then we need to start specifying laws. For instance, the following law distinguishes between the two instances throwError e >> m == throwError e
and this now clearly indicates that EitherT e (WriterT Log) is wrong while WriterT Log (Either e) is fine.So how do we specify what additional laws are needed to cut down the free product of the effectful languages? Dunno, that's a hard one. You could clearly do it using dependent types, but that's still today very expensive.
But given that we literally lack proper information to make a choice it's very important that all of those choices are allowable. It's my position that there is no meaningful default. It's also my position that the `mtl` style free products are perfectly acceptable.
Re: What Color Is Your Function?
#54If you have something that is not async mixed in with something that's async, you can still add it to the promise chain and it will resolve right away. If you have a library that uses callbacks or some other thing, you can just wrap it such that it now uses promises. And then of course you can always look for alternate libraries that use promises from the start and skip step as well.
I've found that using promises for everything works super well. There is no confusion or doubt at all. Everything has the potential to branch into async at any time with no consequences and without complicating the flow. And an additional benefit is that rather than checking for errors after any operation you do, you choose where to check for errors. When a promise rejects, it skips everything else in the chain until it gets to a catch. So rather than running 4 async operations and doing an "if error do this" after each operation kind of deal, you can catch the error in once place and handle it once. Promises surpress the error in the promise chain until you choose to handle it, which is dangerous if you don't understand how promises work, but really useful once you do.
There are really solid promise-based libraries for all common operations in node right now. When.js for general promises, composition, and coercion, rest.js for network requests, bookshelf and knex for database connection and orm stuff, etc. If you are a js developer, give them a shot!
Don't get me wrong, I'm not trying to claim that this is better than any other language-level construct by any means, but if you are working in javascript, where you have to deal with javascript's limitations as a language, from experience I can say that working in an all-promises environment makes things quite pleasant.
Re: What Color Is Your Function?
#55No actor-model based language has this problem, so perhaps all it comes down to is baking in the right(or even any decent) concurrency support from the start, at the language level.
Of course they have. Well, everything is nice and dandy until your actors never block. As soon as you start blocking, your async model has the same problems as threads have. And you cannot really write real-life systems without blocking actors. Ask Erlang programmers whether they have dealt with this kind of stuff.
Re: What Color Is Your Function?
#56Earlier quoted context omitted.
Sure it is! The effect `(MonadTeletype m, MonadNow m) => m a` is just as real as IO. There's nothing special about IO except that the Haskell RTS knows how to interpret it. I could, for instance, build a pure interpreter of those effects into, say, a stream transformer or compile it into a different language (though we'd have to do some tricks to expose Haskell's name binding). If you want your lock obtained/lock rel…
> There's nothing special about IO except that the Haskell RTS knows how to interpret it. But that is what makes it an effect. Sure, you can model effects in a "hosted" language this way, but that's not what we mean by effects.
As another example, it'd be completely possible to write your own IO and interpret it in another language. You can read about this on Edward Kmett's blog where he talks about implementing IO for Ermine [0]
http://www.tuicool.com/articles/I3EJVb
Of course, there's something important that makes us want to differentiate "real world" side effects from internal "model effects". Ultimately, from a correctness and reasoning POV, there ought to be no difference. From a practical point of view, some models are more interesting or important than others. But as a compiler writer you're put right back into the same hot seat.
[0] Unfortunately, his blog appears to be OOC right now, so here's a weird chinese mirror!
Re: What Color Is Your Function?
#57A pain, but still not that bad.
Re: What Color Is Your Function?
#58I don't really consider this solved in languages or runtimes that lack green threads. If you want to make 300,000 threads in Lua or Go, go right ahead, but if you port that application to Java you're going to have a bad time. An orthogonal useful thing that is sometimes not solved in languages with green threads is the ability to copy continuations. If you have call/cc or coroutine.clone, you can e.g. use rollback ne…
In Java itself perhaps, but with Java you can use lightweight threads via Quasar. http://blog.paralleluniverse.co/2013/05/02/quasar-pulsar/
"a single machine can handle millions of them"
Re: What Color Is Your Function?
#59Seems like there are couple things going on here. Accusation that asynchronous implementations in all languages are problematic, with which I don't think anyone would disagree. Suggestion that threads are way better than other asynchronous implementations. I don't agree that makes things better or somehow different. You still have disjointed code. I would add this as a third to Fowler's famous quote about two hard th…
I don't think that's true. The author mentions several languages that use different solutions:
* Java uses threads
* Lua and Ruby use cooperative multitasking with coroutines and fibers, respectively
* Go uses goroutines, which are coroutines multiplexed onto threads
There are definitely similarities, but not all are threads. The common element is that each solution involves keeping separate call stacks. (The author mentions this too.)
> You still have disjointed code.
I disagree. In Go, I can write an HTTP server that never uses the "go" keyword, yet it's still concurrent. This is because the net/http package handles the goroutines for me. With Node, I have to use callbacks no matter what.
Re: What Color Is Your Function?
#60Nim[1], at least at one point (I'm looking at the current manual and can't find it documented), had support for tagging functions with a pragma and the compiler would enforce that functions without the pragma can't call function with the pragma outside of a special block. The compiler interpreted certain pragmas like "impure" and "exception" in a special way, outputting a warning when certain language features were used inside functions marked with the pragma. The language manual shows that the compiler still at least supports these special pragmas. It's possible that it never supported custom pragmas and I'm just misremembering.
Interestingly, the author dismisses promises as not a major improvement and calls async/await and generators at least a half-way solution. It turns out that the are just a simple syntactic transform that isn't powerful enough to express everything that coroutines can. Promises, on the other hand, can. Promises are actually a monad: `.then(...)` is the bind function (`>>=`). This is essentially how the IO monad in Haskell works.