Live data from Hacker News

Failing in Haskell

jappie.me

11–20 of 55 posts

Re: Failing in Haskell

#11
post #4

I only used Haskell for small projects. I admire the language, but I found error handling to be one of the weakest and most inconsistent elements. To the point of being annoying and time consuming. Several popular libraries I used threw exceptions for expected failures (like a non 2xx HTTP response) and required wrapping. Even the standard prelude is full of partial functions. (head...). I saw a wild mix of Either, e…

> they generally don't capture backtraces

Backtraces with higher-order functions, lazyness, partial applications, and all the transformations going on (SKI, CPS, or whatever the GHC does), I don't think any kind of backtrace would be legible.

Re: Failing in Haskell

#12
post #7
post #3

> If we need to compose these errors in a larger program we can simply wrap previous errors in a bigger sumtype This approach is being adopted in GHC itself to compose errors happening at different stages of the compilation pipeline: each stage has its own error type which later becomes a branch of the global error type. Another interesting post about errors-as-values in Haskell is "The Trouble with Typed Errors": ht…

The GHC approach you describe is also what people do with Results in Rust, and (analogously) with Java's typed exceptions. The idea is that in a multi-layered program, every layer exposes errors that are semantically appropriate for that layer. So (to pick a silly little example) a database call would expose a DatabaseError, not a raw network error if the connection is interrupted. And so on until you get to the leve…

The ‘head’ function is an unfortunate historical artifact and not the norm these days. In practice there are libraries that expose a head function that returns a value… but better still, well typed programs can avoid the need for it altogether: there are non-empty lists to consider in which head is trivially safe to use, provided one can construct such a value.

One error handling strategy not often employed is to prefer code that is correct by construction. It can’t always be done but it’s nice when you can do it.

update spelling

Re: Failing in Haskell

#13
post #5

I've written small stuff in Haskell a decade ago. I have a soft spot for the language -- it has clearly influenced many notable languages that came after it. But I also admire the patience of anyone who actually manages to use it in practice, there are so many little papercuts that don't get resolved, basically for a decade or more. If I'm cynical, I'd say that's because little practical stuff is often not worth publ…

What you are running into is the pureness of Haskell. The `head` function in Haskell is only partially defined. What you see as an exception is a case where a function is not defined. This is all by intent.

defining a `head :: [a] -> Maybe a` is a very simple matter and definitely something a developer should be encouraged instead of using the prelude.

exceptions in Haskell are not meant to be used as a first class thing, but is the way to ensure a full Turing complete language where it is possible to define non-terminating behavior. Hence it really is by design.

Re: Failing in Haskell

#14
post #5

I've written small stuff in Haskell a decade ago. I have a soft spot for the language -- it has clearly influenced many notable languages that came after it. But I also admire the patience of anyone who actually manages to use it in practice, there are so many little papercuts that don't get resolved, basically for a decade or more. If I'm cynical, I'd say that's because little practical stuff is often not worth publ…

> But I also admire the patience of anyone who actually manages to use it in practice

Nothing you point out gets even close, in my mind, to stuff like null pointers or untyped code. So I wonder what languages you have in mind that require less patience.

> you need IO for that. Which the language makes intentionally hard to use

Well, that is simply not true.

Re: Failing in Haskell

#15
post #5

I've written small stuff in Haskell a decade ago. I have a soft spot for the language -- it has clearly influenced many notable languages that came after it. But I also admire the patience of anyone who actually manages to use it in practice, there are so many little papercuts that don't get resolved, basically for a decade or more. If I'm cynical, I'd say that's because little practical stuff is often not worth publ…

This is why I see PureScript as a better starting point. It was modeled after Haskell, but since it was created in 2013, many of the design choices were to avoid these sorts of things.

Re: Failing in Haskell

#16
post #5

I've written small stuff in Haskell a decade ago. I have a soft spot for the language -- it has clearly influenced many notable languages that came after it. But I also admire the patience of anyone who actually manages to use it in practice, there are so many little papercuts that don't get resolved, basically for a decade or more. If I'm cynical, I'd say that's because little practical stuff is often not worth publ…

What you are running into is the pureness of Haskell. The `head` function in Haskell is only partially defined. What you see as an exception is a case where a function is not defined. This is all by intent. defining a `head :: [a] -> Maybe a` is a very simple matter and definitely something a developer should be encouraged instead of using the prelude. exceptions in Haskell are not meant to be used as a first class t…

The issue as I see it, is that one of the main selling points of a pure language like Haskell, is that you have to explicitly state where a certain class of surprises/failures (from IO) lie, and therefore, you can account for them better, handle them cleanly, prevent them from arising accidentally or in some ways maliciously, etc. Partial functions are another kind of surprise/failure, but they are not at all explicit.

This is a bit strange. It's like caring deeply about whether printf fails, but not so much whether array indexing is out of bounds. Haskell has a great story for both kinds of issue, and even its exceptions are better than panics IMO, even if they are about as tricky to use as POSIX signals, but it is relatively obscure and stigmatized to do a gross thing like use unsafePerformIO, but actually quite common/natural and accepted to use head. Lots and lots of people know to do the right thing for the latter, and there is something of a community push to avoid them, but it's just interesting to note how easy it is to make one mistake versus the other, when both matter a lot. One is treated as fundamental, and the other is not, but day to day, both kinds of issue lead to a similar magnitude of headaches, so the disparity is noteworthy.

I'd love it if even just the type signature recorded that exceptions are possible, even if there is no practical effect on how or where it is used.

Re: Failing in Haskell

#17
post #14
post #5

I've written small stuff in Haskell a decade ago. I have a soft spot for the language -- it has clearly influenced many notable languages that came after it. But I also admire the patience of anyone who actually manages to use it in practice, there are so many little papercuts that don't get resolved, basically for a decade or more. If I'm cynical, I'd say that's because little practical stuff is often not worth publ…

> But I also admire the patience of anyone who actually manages to use it in practice Nothing you point out gets even close, in my mind, to stuff like null pointers or untyped code. So I wonder what languages you have in mind that require less patience. > you need IO for that. Which the language makes intentionally hard to use Well, that is simply not true.

[deleted]

Re: Failing in Haskell

#18
post #4

I only used Haskell for small projects. I admire the language, but I found error handling to be one of the weakest and most inconsistent elements. To the point of being annoying and time consuming. Several popular libraries I used threw exceptions for expected failures (like a non 2xx HTTP response) and required wrapping. Even the standard prelude is full of partial functions. (head...). I saw a wild mix of Either, e…

I have to echo your point on inconsistency.

Our company uses Haskell and the Haskell team love to define their own solutions which make things even more inconstant. For error handling they end up using an extensible type-level-list containing possible error types, embedded in an extensible effect monad. We also have list, array, vector, and our own collection types in the same place.

It feels like everyone want to make things better by using/making something new, instead of making them consistent.

Re: Failing in Haskell

#19
post #5

I've written small stuff in Haskell a decade ago. I have a soft spot for the language -- it has clearly influenced many notable languages that came after it. But I also admire the patience of anyone who actually manages to use it in practice, there are so many little papercuts that don't get resolved, basically for a decade or more. If I'm cynical, I'd say that's because little practical stuff is often not worth publ…

> But I also admire the patience of anyone who actually manages to use it in practice, If I'm cynical, I'd say that's because little practical stuff is often not worth publishing papers about.

I feel my impatience pushes me towards Haskell if anything... local-reasoning for instance rather than "understand this entire call chain" requires less patience and is easier to get right.

> there are so many little papercuts that don't get resolved, basically for a decade or more.

I've been using Haskell a decade in practice, can you tell me what papercuts you had in mind? I'm assuming I and other real world Haskellers might just see them as much less of a priority all things considered, but I'd like to be sure I'm not missing something.

Re: Failing in Haskell

#20
Adressing the whitespread conception "It is hard to programm in Haskell because it is pure":

If you can write python, you can write Haskell. Don't believe me?

1. Write your program completely in the IO Monad, in a huge do-block

2. Factor out as much pure functionality as possible (= Have as little code in your big IO-programm as possible.)

Start at 1. and iterate 2. as many times as you please. It will already be a program that prevents many traps that would bite you in other langauges. Haskell knows exactly whether you are looping over an array of strings or an array of chars.

(Why all the buzz about pureness, effects and so on? Well, with Haskell you can design with a high granularity and reliability what sideeffect is caused where. But you are not forced to use that feature.)

Other tipps:

- Build small projects.

- Read as few tutorials on monads as possible. You might even get by with 0.

- The trifecta of Haskell typeclasses are the functor, applicative, monad. I would advise you to not try to understand their mathematical origins, but just look up how the are used. They will crop up naturally when you build even small projects and then they will make sense.

Post reply on HN