4 ms·
And why would you want to redo the idiomatically complex part in Haskell (there are probably thousands of monad tutorials just to explain why I/O in Haskell nee
by yason 12y ago
And why would you want to redo the idiomatically complex part in Haskell (there are probably thousands of monad tutorials just to explain why I/O in Haskell needs to be wrapped in a monad) also in similarly a complex way in Clojure which, however, could actually handle I/O and side-effects in a controlled way just fine without making an (academic) mess out of it?
You need to use monads to get around Haskell's limitations imposed by the decision to target complete purity just to do simple things like I/O but no matter what I/O is still not pure (something like readline can never be pure even if it wanted to) and thus you're, in one way or in another, forced to separate the static, pure and functional parts of your program and its dynamic part with side-effects.
Haskell does it with monads which, as a concept in itself, is a generic way to reason about state, but IMHO the exactly best part of Clojure is that it offers several ways to manage dynamic state in a controlled way without forcing you to go 100% pure or 100% impure. Why break that, except as a mental exercise?
- tel 12y agoThis is so misinformed it isn't even wrong. * IO doesn't have to be wrapped in a monad, there are other models * Clojure cannot handle IO/side effects very well (compared to any language with effect typing) * Input and output are not pure, but the `IO` type itself is pure. Rather, constructions of the IO type are pure and then the runtime can interpret IO values impurely. * The entire point is to separate the impure from the pure. It's not that you're forced to, it's that you desire to. * Monads are not, in themselves, generic ways to reason about state. They are far more general. * Anything that is not 100% pure is 100% impure. Without purity guarantees you cannot trust code you call upon to not do side effects. This breaks local reasoning.
- taeric 12y agoI can't help but disagree with your final bullet. You won't have "contractual and checked by the compiler" trust in code you call upon, but it is quite common to trust the code that you call in any language to do just what it claims it will do. Consider, do you really think that code was lacking local reasoning before the likes of Haskel? It is arguable that things were more difficult then, but the argument is still out that things are easier now.
- tel 12y agoLocal reasoning is absolutely impossible unless you have some kind of contract which ensures that your (local) code is pure. This is almost definitional. What I haven't claimed is that no other fragment of code in another language can be pure. In nearly any language (1+1) is pure. My point was that literally any impurity inside of a fragment of code makes the whole thing impure (in most cases) and therefore destroys local reasoning. The "in most cases" bit above is important because there are ways to "purify" a code fragment so that code which uses it cannot witness the impurity inside and therefore it restores local reasoning "above" that level. The ST monad is such an example.
- taeric 12y agoI don't think "absolutely impossible" means quite what you think it means. Again, I will make no claims that it is easy. And in some cases you may wind up with some global reasoning entering into the coding process. Honestly, with how many solutions I've seen with tons of "locally pure" parts that were a bloody mess to deal with, maybe some "global" reasoning is called for.
- tel 12y agoI'm willing to consider that I might be wrong, but here's the argument. If I am looking at some code which includes computation (by which I include function calling but also reference access which is sometimes trickily ignored as a computation) then I cannot assess the behavior of this code without knowing either (a) the computation is side-effect free and therefore has a mere value semantics or (b) it is not and can potentially be affected by or affect non-local parts of the code. To hit case (a) I don't need a language which enforces purity, but I do need to know that everything "beneath" where I'm standing is pure. In this case, uncertainty, even tiny amounts of it, whittles away (a) entirely and leaves me in concern (b). I'm not saying that global reasoning is bad or infeasible, but I am saying that lacking purity you cannot trust local reasoning until you isolate the pure fragment. For instance, you might state that (!x + !y) involves the global reasoning of what the values of (x) and (y) are but is local reasoning otherwise. I'd argue that actually local reasoning is destroyed until you refactor this code as let x_value = !x in let y_value = !y in (x_value + y_value) where the parenthetical fragment is now pure and local as the side effects were sidelined into the let clauses. I previously wasn't saying that "locally pure" code is preferable to globally reasoned code. I'm not completely certain that I would say that in all cases. I feel very confident though that it's (a) the right default and (b) something that should be used to a far greater degree than most code I see written which more or less demands global reasoning to do anything non-trivial at all.
- _delirium 12y agoI don't think the post is really arguing what you're arguing against here. It says it's doing an "experiment", for "fun and learning purposes". It's not advocating removing side-effectful I/O from Clojure, just looking to see if Haskell-style I/O is possible in Clojure. I don't think it's really too "academic" for someone to do something for fun and learning, and post about it on the internet...
- deleted 12y ago[deleted]
- noelwelsh 12y agoFollowing up _delirium's post, there are advantages to the Haskell approach: separating structure from interpretation of computer programs (pun very much intended) and compositionality of said programs. I talked a bit about this first property in the context of the free monad here: http://underscore.io/blog/posts/2015/04/14/free-monads-are-simple.html http://underscore.io/blog/posts/2015/04/14/free-monads-are-s... It is certainly worth exploring other paradigms to understand the advantages and disadvantages they bring.
- whateveracct 12y agoYou're the top post of this HN thread but you're making sweeping statements of fact about Haskell and other topics you clearly don't have a working understanding of. You should edit your comment so as not to mislead people about the truth. The statement about monads being tied to state is particularly wrong and confusing to the uninitiated.
- tjradcliffe 12y agoBut the whole point of Haskell is to make claims that confuse the unitiated, isn't it? Because that's excactly what every tutorial that claims "Haksell is a pure langauge" is doing when it then goes on to say "Haskell can do I/O" without explaining that unlike every other language the unitiated reader has ever encountered, Haskellers have chosen to define "the langauge" in such a way as to exclude "the runtime". I really don't get why this point is not made clear in all Haskell discussions up-front, but instead Haskellers insist on repeating the empty mantra "Haskell is a pure language" as if they were using the term "language" in the standard way rather than redefining it in a carefully constructed way so as to make their claim true. This is terrible pedagogy on par with people who introduce negative generalized temperature or resistance without first explaining that they are generalizing the concept. And it obscures one of the coolest aspects of Haskell, which is that it is an impure language (using "language" in the standard way, which always includes the runtime) that has very cleverly packaged its impurity such that reasoning about the code still gets most of the advantages of purity. "Haskell has a pure syntax that is interpreted by an impure runtime" is more accurate and far less confusing.
- arielby 12y agoC/C++ don't have much of a runtime too (libc's "runtime" component is often not used, and libstdc++'s is rather controversial). Standard Haskell functions (with types like `a -> b`) are pure, unlike (most) other mainstream-ish languages. Of course you can do IO, which of course is impure, but it is cleanly separated from non-IO.