6 ms·
> An example of this is the concept of resumable exceptions. During Semantic's interpretation passes, invalid code (unbound variables, type errors, infinite rec
by phodge 7y ago
> An example of this is the concept of resumable exceptions. During Semantic's interpretation passes, invalid code (unbound variables, type errors, infinite recursion) is recognized and handled based on the pass's calling context. ... Porting this to Java would require tremendous abuse of the try/catch/finally mechanism, as Java provides no way to separate control flow's policy and mechanism. And given Go's lack of exceptions, such a feature would be entirely impossible.
Not knowing much about FP, It'd be great to see a more in-depth article explaining this problem domain a bit more and showing some side-by-side examples of Haskell's specialized call sites compared to a Java try/except/finally solution (although Python would be a better procedural exception-based language to compare to)
One of the main reasons I don't care much about Haskell is because without any side-by-side comparisons of Haskell vs <insert procedural language> I don't understand what the Haskell advantages are, and I don't know when I'm dealing with a problem space where Haskell would help me.
- k6k7f7uky8ki 7y agoYou mean examples like Rosettacode has?
- cstrahan 7y agoNot Java or Python, but here’s some Ruby: https://www.honeybadger.io/blog/how-to-try-again-when-exceptions-happen-in-ruby/ https://www.honeybadger.io/blog/how-to-try-again-when-except... The above article talks about exploiting Ruby's support for call/cc to do something similar. A noteworthy difference: Ruby's support for call/cc is baked into it's runtime, while in Haskell you can implement call/cc as a normal library. This is done by leaning on Haskell's monadic "do" syntax and a suitable implementation of the Monad class. http://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-Cont.html http://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Mo... I'm rooting from my phone, so I can't type up a this-vs-that. But maybe that piques your interest and you can read up on Haskell and programming with monads.
- hardwaresofton 7y ago> One of the main reasons I don't care much about Haskell is because without any side-by-side comparisons of Haskell vs <insert procedural language> I don't understand what the Haskell advantages are, and I don't know when I'm dealing with a problem space where Haskell would help me. This is one of haskell's biggest problems. It's just enough outside of the normal flow of imperative languages (yet usable for the same problems) that you can't tell how much of an improvement it is unless you try it. Also, people who write haskell are more inclined to share lofty/abstract/interesting-to-other-haskellers code rather than your normal day-to-day code that is massively improved/safer and benefited from haskell's features. I've mentioned this before, but one example of where it became apparent to me how much haskell had changed what I expected from language was non-nullable types. It's starting to be really common in languages now (typescript, kotlin, etc), but if you are used to writing imperative languages, the worry of nil/None/null is ever present, and a concept like Optional<T> is actually quite foreign looking. If you really think about it, it means that none of your language is safe -- none of your functions are safe because they said they wanted a String but you might have gotten a null that looks like a String to the typechecker and will blow up at runtime. Another key improvement in haskell is the removal of class-based code-sharing (i.e. inheritance) -- the separation of behavior and data is really important, and most languages are starting to come around to this now (go w/ structs + interfaces, java w/ data classes, kotlin w/ data classes, rust w/ structs + traits), but haskell (and other ML languages) have been there for a while. Yet another key improvement in haskell is the errors-as-values paradigm that is everywhere. If some function has a possibility of failure, then it should return `Maybe TheThing` or `Either AnError TheThing` (see how nice and legible those types are?) -- this forces explicit checks on failure and allows cases where there isn't a chance of failure (just `TheThing`) to speed ahead without nullchecks and be fairly certain. This actually pressures you into trying to sequester failure across your codebase -- you try to write functions that have signatures like `TheThing -> SomeArgument -> OtherThing` (see how legibile that is?), to minimize on the amount of `Maybe x` or `Either error x` you have to deal with -- this is often if not always good for codebases. Maybe this is something I can help with, I write about pedestrian haskell a bunch, and I've been meaning to do a blog post on why haskell is better <your language>, something to really rustle the jimmies. BTW, the quote about resumable exceptions is actually referring to a concept called a monad, which can be incredibly hard to grasp if you don't look in the right places (there are a lot of bad tutorials out there), or don't give your brain long enough to marinate in the concepts. If I were to take a stab at explaining it simply, in this case it's like a combination of exceptions-as-values (i.e. not go's approach, and not java's approach) and the value that is being passed around has enough state in it to continue stop, fix itself, whatever else. When something goes wrong in most imperative languages, you kind of get the hell out of dodge, and you lose access (usually) to whatever work was done up until the function boundary -- it doesn't have to be this way but it usually is.
- dmix 7y ago> Also, people who write haskell are more inclined to share lofty/abstract/interesting-to-other-haskellers code rather than your normal day-to-day code that is massively improved/safer and benefited from haskell's features. When Rust started getting flooded with the "web" crowd of ex-Rubyists and the like there was a lot of push back from the traditional systems people (for better or worse). But one of the benefits is that these guys are typically far better at communicating and selling languages to the general developer public. I too have run into countless examples of these "beautiful" Haskell code examples but when it came down to doing real work I felt like I was left to either figure it out myself, try to connect a more abstract blog post to more practical applications, or left reading some auto-generated Haskell/library API documentation (75% was the last one). Maybe Github and Facebook et al can lend some of these resources to teaching Haskell to the public and releasing well-documented libraries which set a standard for others to follow? It may have a high learning curve like Rust, but it's far from impenetrable for your average developer.
- hardwaresofton 7y ago> When Rust started getting flooded with the "web" crowd of ex-Rubyists and the like there was a lot of push back from the traditional systems people (for better or worse). But one of the benefits is that these guys are typically far better at communicating and selling languages to the general developer public. I 100% agree -- this is the crowd that brings the hype (for better or for worse). I guess it's another one of those life lessons, but projects need both types of crowds (and to be honest it's not like there's a strict separation, lots of people fit in both camps). I think Rust is actually going to eat a ton of what could have been Haskell's lunch -- it's a great typesystem for the traditional imperative language crowd and awesome performance for the ML crowd, and a completely new paradigm of data safety that neither of those crowds had before. These days I struggle to choose Haskell, but have settled on Rust for "performance critical" things (I don't really write truly low level software so take that with a grain of salt), and Haskell for everything else. > I too have run into countless examples of these "beautiful" Haskell code examples but when it came down to doing real work I felt like I was left to either figure it out myself, try to connect a more abstract blog post to more practical applications, or left reading some auto-generated Haskell/library API documentation (75% was the last one). > Maybe Github and Facebook et al can lend some of these resources to teaching Haskell to the public and releasing well-documented libraries which set a standard for others to follow? It may have a high learning curve like Rust, but it's far from impenetrable for your average developer. Hugely agree, but I think it's gotta be a community effort. FPComplete is out there doing stuff, and there are lots of individual bloggers, but Haskell needs more people writing "pedestrian" programs. I think it's one of the main ways of contributing to a language that is often overlooked. I don't have any numbers, but learn you a haskell for great good has probably lead to thousands of new haskell devs over it's lifetime, even if the information in it is outdated (and some consider it not a good starting point). To compound all this, haskell also has a documentation problem -- the machinery is there but it often doesn't get written, or people don't include the "getting started" use cases. Most popular libraries are workable but some others aren't, so it's intimidating until you really start to see the types as sufficient for understanding. Small shameless plug, I try to write about haskell and am in the middle of a post where I make a CountMin data sketch right now, I'm not quite done with it but hope to have it done this weekend. I feel in that way I'm at least doing something to help the haskell community.
- chas 7y agoI wrote a something[0] that demonstrates Haskell programs side-by-side with a Java program for a super toy problem. It goes on to explore more complex Haskell abstractions which implement the same simple program using less approachable techniques. It is primarily meant for helping people understand how the abstractions work, rather than make an argument for when they are good to use, but it might give you enough background to understand the discussion around Haskell abstractions. [0] http://reduction.io/essays/rosetta-haskell.html http://reduction.io/essays/rosetta-haskell.html
- namelosw 7y agoI think it's hard to do just side-by-side comparison. Just imagine you just go back to 90s and convince C++ fans using Java. They are all general purpose programming languages, just with some better/different design decisions to make things safer or relatively more/less expressive. Similarly, the difficulty to explain Monad is Monad itself is pretty abstract and general. You can describe what it is, but it's hard to guarantee what the audience get from you. Someone says it can solve asynchronous programming issues, then someone will think it's something just for solving this kind of issues. Same as solving null pointer exceptions. After all, it's an abstract representation of sequencing computations with effectful context. But the last one is much harder to understand than the formers. An equivalent thing is expressing the concept of the "variable" to a mathematical audience who never heard of a computer. They can definitely understand part of it, but not what you want to express.
- james_s_tayler 7y ago>Similarly, the difficulty to explain Monad is Monad itself is pretty abstract and general. A Monad is just a Monoid in the Category of Endofunctors.
- mikojan 7y agoThis. What's so hard to understand about that?
- alexanderdmitri 7y agoWould I be correct in saying you just encapsulated the monad state type `this` in an identity `that` by creating a monad transformer out of `understand`?
- PaulAJ 7y agoFor the non-Haskell readers, I should point out that this is just an old joke in the Haskell community. If you want it explained, see here:https://stackoverflow.com/questions/3870088/a-monad-is-just-a-monoid-in-the-category-of-endofunctors-whats-the-problem https://stackoverflow.com/questions/3870088/a-monad-is-just-...
- wizzairflyer 7y agoThis guy wrote 3 really short blog posts about doing Haskelly-stuff in C++. [1, 2, 3] They are pretty concise and [2] especially did a good job of making me understand some of the power of Haskell. [1] https://www.syrianspock.com/functional%20programming/software/2018/01/22/functional-cpp-adventures-optional/ https://www.syrianspock.com/functional%20programming/softwar... [2] https://www.syrianspock.com/functional%20programming/software/2018/02/03/functional-cpp-adventures-function-composition-on-steroids/ https://www.syrianspock.com/functional%20programming/softwar... [3] https://www.syrianspock.com/functional%20programming/software/2018/03/12/functional-cpp-adventures-either-error-handling/ https://www.syrianspock.com/functional%20programming/softwar...
- golergka 7y agoI'm only a Haskell beginner, but I have solved similar task, with parsing that may fail, in CIS 194 course. The solution was based on applicative functors, and I really don't think that Java or other languages have anything like it. Here's the lecture: http://www.cis.upenn.edu/~cis194/spring13/lectures/10-applicative.html http://www.cis.upenn.edu/~cis194/spring13/lectures/10-applic... and PDF of the assignment: http://www.cis.upenn.edu/~cis194/spring13/hw/10-applicative.pdf http://www.cis.upenn.edu/~cis194/spring13/hw/10-applicative.... Here's my solution of it: https://github.com/golergka/cis194/blob/master/Homework11/src/AParser.hs https://github.com/golergka/cis194/blob/master/Homework11/sr... I hope it's readable enough to illustrate the overall concept - but please bear in mind that I'm a beginner and probably have made dumb mistakes. If you have any criticism or suggestions, I would love to hear and learn from them: learning Haskell is the first time in my software engineering self-education where I wish I had regular contact with instructor or a mentor.
- mbrock 7y agoI’m a bit skeptical of the difficulty ascribed to doing something like resumable conditions in a Java system. You could have a per-thread singleton stack of handler objects. To raise a resumable condition you call a method on the stack that searches outward for an active handler to ask for a restart option and just returns it. If none is found an exception is thrown to unwind the call stack. (Common Lisp has restartable conditions native to the language and this is essentially how it works. Conditions just don’t unwind the stack until no restart is available.) Haskell monads can easily model other interesting control flow structures but this is basically just a syntax nicety of the do notation that lets you avoid writing nested lambdas to represent continuations. If you’re okay with heavy lambda nesting in Java you can do it all by just implementing whatever monad you like in Java—although the type system isn’t as glorious when it comes to higher-order polymorphism and inference.
- norswap 7y agoThis is trivial to do in most languages (including Java and Go) if you just stop to think about it for a couple of minutes. Just pass some kind of context object down the call stack (or make it available as a global — make it thread-local if you need). Then when an error occurs, just call this handler and voilà! This is, in fact, pretty much what Haskell does. Except this handler is in a typeclass instance, and this typeclass instance is passed down the call stack, it just doesn't appear in the parameter lists but in the type signatures. It's a bit lighter syntactically, but ultimately it's the same thing.
- rauhl 7y ago> > During Semantic's interpretation passes, invalid code (unbound variables, type errors, infinite recursion) is recognized and handled based on the pass's calling context. … And given Go's lack of exceptions, such a feature would be entirely impossible. Nonsense! It’s completely possible — you just have to be willing to abuse a few of Go’s features in order to do it. First off, Go does have a standard calling-context (i.e. dynamic context) mechanism: context.Context[0]. All you need to do in order to track stuff in the calling context is stash an object in the … context. Given this dynamic context mechanism, you next need a way to represent handlers. That’s easy: a handler is a function which takes an exceptional condition and either handles it or returns; handling consists of a transfer of control. Fortunately, Go has a control-transfer primitive as well: panic. So to handle a condition, a handler just panics — something higher up the call stack can use defer to catch the panic and continue execution. That leads to the next component necessary: a way to provide resumption points, or restarts. A restart is just a function which is invoked by a handler, potentially with arguments, and which when invoked continues execution from its establishment point. This can be done with defer. So it’s perfectly possible with tremendous abuse of Go’s panic/defer mechanism, no different from Java. See this gist: https://gist.github.com/r13l/2911f93cbe66fb4ed50f9d9eb1eb252e https://gist.github.com/r13l/2911f93cbe66fb4ed50f9d9eb1eb252... Honestly, I don’t even know if I’d call it tremendous abuse, although it is somewhat abusive. Abstracted in a library, it might even be somewhat useful. It’s off-the-cuff — I haven’t fully considered the semantics of the different context objects being passed around. 0: https://golang.org/pkg/context/ https://golang.org/pkg/context/