4 ms·
> It's easier than achieving Haskell-like defect rates in languages that have ad-hoc built in solutions to the same problems, IME. My first Haskell program typ
by atilaneves 8y ago
> It's easier than achieving Haskell-like defect rates in languages that have ad-hoc built in solutions to the same problems, IME.
My first Haskell program type-checked and passed all tests. It was incredibly broken. As in it didn't work at all. I understood monads and it didn't help one jot.
Monads in other languages _can_ be helpful. It pays off to know what one is. But in Haskell, more often than not they're being used to solve problems other languages don't even have in the first place.
> Disagree. Certainly it's a lot easier than solving the same problem by hand.
How? Anyone knows how to write a test double by hand. Most people can use a mocking framework. The visitor pattern is in the GoF book. These are well known and don't involve completely changing the type signature of the code you're writing just so you can interpret it. And let's not even mention Lisp.
> Agreed, but again, easier than achieving the same defect rates without them.
Not really. Write pure code, test it, have a thin layer of side-effects around it. The transformer stack is solving, again, problems only Haskell has. I don't need the state monad anywhere else, so I don't need to layer it on top of anything. In a language with exceptions, ditto. And so on.
> Easier than understanding dozens of ad-hoc informally specified implementations of half of them, which is what working in an ecosystem without them boils down to.
I would bet good money that in my old team I wouldn't be able to explain what an applicative functor is to 90% of them if I had one month of full time training.
> Perhaps not, but easier than achieving the same defect rate without them.
Solves, yet again, a problem only Haskell has.
- lmm 8y ago> Monads in other languages _can_ be helpful. It pays off to know what one is. But in Haskell, more often than not they're being used to solve problems other languages don't even have in the first place. Every language faces the same problems; your only options are to not solve the problem at all, solve it in an ad-hoc way, or solve it with a general feature. E.g. every language faces the problem that error handling can be quite boilerplatey. Bad languages don't solve this at all. Somewhat better languages offer an ad-hoc language feature like exceptions, which are superficially nice (indeed superficially nicer than monadic error handling). But every ad-hoc language feature is one more thing to keep in mind when working or debugging, so they all come at a penalty to your defect rate: exceptions lead to "magic" control flow which can lead to resources not getting closed on error paths, seemingly-innocuous refactors changing behavior, and so on. > Anyone knows how to write a test double by hand. Most people can use a mocking framework. Until you ask them to test code that relies on something async, and then they'll write flaky tests, or no tests at all. And I don't think I've ever seen a decent test double for something like a database (most people give up and use an in-memory one). Even those who write tests tend to end up with tests that are much more boilerplatey than main code and not kept up to date, because mocking frameworks rely on magic reflection that means you can't refactor code that uses them the normal way. > Write pure code, test it, have a thin layer of side-effects around it. And when the business logic you're implementing is inherently coupled to effectful questions and effect actions, what then? Distort your code, invent some ad-hoc datastructure to represent a half-complete business decision that needs to rely on the answer from some other service? > I don't need the state monad anywhere else, so I don't need to layer it on top of anything. In a language with exceptions, ditto. And so on. Well, you need state, you need error-handling; either you do these things manually and directly (painfully verbose and unmaintainable, leading to high defect rates), you do them in a "magical" unmanaged way (high defect rates because you can no longer know what code interferes with what other code), or you manage them explicitly, at which point you need a way to interleave managed effects. > I would bet good money that in my old team I wouldn't be able to explain what an applicative functor is to 90% of them if I had one month of full time training. Bet you could. I simply don't believe that anyone who can understand the "visitor pattern" or "observables" or "factories" or whatever the OO pattern of the week is could struggle with applicative functors. It's an interface consisting of two functions of at most two arguments. It's really not that hard. > Solves, yet again, a problem only Haskell has. Not so; every substantial system I've seen has ended up needing some way to pass a "patch" or "change" around between different bits of code. The only choice is whether you do it in an ad-hoc way or a standard one.