Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Part of the reason I enjoy languages like Haskell is because of the abstraction maximalism enshrined at the language level, rather than the coding level.

We all agree on what an Applicative is supposed to do. The challenge shifts right in the idea-to-code pipeline to finding the right Applicative for the problem. Most OO design patterns have natural, well defined equivalents in such an environment, but the difference is this way helps minimize the amount of project specific abstractions you have to deal with.

The downside as a beginner is of course a greater upfront cost to learning the language, and quite frequently opening up another Haskeller's work and realizing there are like 12 compiler extensions you've never heard of that you now need to grok. But even there I would argue that's a net win: you can carry those compiler extensions with you to all projects in the future. (The downside as an expert is realizing you have to get a PhD to get a sense for how much RAM your cats will gobble up!)



We know what Applicative and Monad (forgetting the burrito) do because the have mathematical LAWS. If a piece of code uses Applicative or Monad you know it’s behaviour due to the Applicative/Monad mathematical laws.

No OO design pattern has a law, they are a loosely defined concept/pattern which means they are open to personal interpretation/customisation but no concrete law to say exactly what it is and its expected behaviour/output.


> If a piece of code uses Applicative or Monad you know it’s behaviour due to the Applicative/Monad mathematical laws.

Well, we actually only know what it is supposed to do. The laws are not enforced, so it is perfectly possible to implement a type class that violates the laws of the type class.


Several test frameworks implement Law Testing which will test your instances for lawfulness as long as you can generate instances of your data structures. E.g. https://hackage.haskell.org/package/hedgehog-classes . So you only need to be able to generate instances and you get comprehensive tests for free, so that's nice too.

It is also the case that implementations of these very abstract classes typically only also have very few implementations that make any kind of sense type-wise and that the 'obvious' one is correct.

(Just to preempt: Yes, tests aren't proof, but such is life without a full proof system in the language. In practice, I've found property-based testing sufficient.)


Oh, I know and I'm not arguing against anything you've said. I just wanted to express - for people who don't know Haskell - that while the laws exist, they are not (as of now ;) enforced or checked by the type checker.


No worries, I was also just trying to add info.


Your observation reminds me of Philip Wadler's Strange Loop talk [1], where he states that some languages are discovered, whereas most languages are merely constructed.

I think he would have agreed to Haskell (or at least, languages based around lambda calculus) is more in the first category, whereas Java, C++, Smalltalk, Javascrip (ie. OO languages) are in the second. Computational fundamentals versus engineering problems.

[1] https://thestrangeloop.com/2015/propositions-as-types.html


But Monads are like what you compose. The equivalent in OO would be the semicolon. You still need business logic that follows messy life / human rules no matter what paradigm you use.


I think these are two wildly opposed world. What the industry calls OO is just a way to try to avoid large business failure. Other paradigms were more about computation, the logical basis is way way deeper. These people like to own all computational layers very precisely from parsing, to compiling, to algorithmic analysis. Enterprise/Application coding is not about that, it's how to bridge the customer / IT gap with something not too horrendous and still adaptable enough to handle market chaos.


I am not seeing how these claims hold up in practice.

> law to say exactly what it is and its expected behaviour/output. What does Monad laws say about expected _behaviors_ of some Monad?


They specify part of the behavior. But at least it always tastes like a burrito!


As a fellow haskeller, I agree on that the language has very good abstraction capabilities.

On the specific example in the blog post though I can only say that there are so many times I've been down the clean code path and it's more often not another person, but the future you, into whose foot you are shooting. Abstraction is not beneficial when you need to study it later to understand it again.


> Abstraction is not beneficial when you need to study it later to understand it again.

This is where a good study routine comes in. I study Haskell like I study all things of any long term importance, using an Anki deck. It takes me longer to start using a new abstraction, but once I have it it's pretty much there for life, due to my daily commitment of half an hour or so to my reviews. It makes far less sense, of course, to do this for a one-off abstraction I had to apply to a specific project, so this naturally tilted me over the years to work more and more in loss like Haskell.

(N.B., I do not state this as a prescription. I think this is well above and beyond what most people expect of themselves professionally, and that is okay. Everything in life comes with tradeoffs.)


This is really interesting to me. What exactly do you write on the anki cards? I cannot really image learning a haskell abstraction by mere memorization. How can you learn it without actually applying it to a real problem. Often times the hard part is to know when to use which abstraction. How do you learn this using flashcards?


What you detail is pretty much how you would recognize it. You write out a brief summary of the high level problem, and then ask yourself "which abstraction would you reach for first, absent any other information?"

The latter part is often implied, but it's best to make it explicit. You're trying to build up expert intuition, which means allowing for the fractal nature of software development to mean you might be in the 20% of times where this won't work for you.


The OP would have done better to use more OOP principles, unless eschewed by the team in general--then I'd probably work elsewhere. The place where OOP has the most natural fit is implementation of GUI widgets and their editors. I've written a few myself.

The 'rule' that unifies OOP's other rules is tell-don't-ask. So for the example at hand we have the handles which are shared in a known way and I presume shape-specific control points (e.g. circle may have center, radius). Then a change of a box handle could call a updateControlPoints(changedHandle). There would also be updateBoxHandles(changedControlPoint). There may be other clean splits, but that's how I'd do it.


> We all agree on what an Applicative is supposed to do.

Maybe. But not on which parsing library to use (parsec? megaparsec? attoparsec? regex-applicative?), on whether to use Data.Text.Strict or Data.Text.Lazy, on how point-free the code should be, on whether to use "." or ">>>" or any other combinators, on which language extensions to use...

I like Haskell, but it suffers from similar problems as any other language: people can't really agree on the best way to do things


> The downside as an expert is realizing you have to get a PhD to get a sense for how much RAM your cats will gobble up.

Go one step further with affine types and use Rust. You get haskell type system with predictable performance.


> You get haskell type system

No. When trying to use Rust's traits like Haskell you learn really fast why higher kinded types are needed.


What is Rust missing out on?


Oh, wait, does Rust not have kinds? That's a bummer.


Rust has GAT's which have the same expressivity as HKT's. But many Haskell patterns turn out to be unidiomatic in Rust due to extra overhead. (For instance Rust has multiple function-like traits that access their environment differently. There's no equivalent to this in Haskell of course; GC and default boxing choices for Haskell types obviate the issue, but this is not zero cost.)


I know, I know. It's very silly of me not to pick up Rust when I've already got all of its forbearers in my bones. Someday, once I've finished studying everything else I need.


oh, oh my. The golang opposite where you don't have language extensions and should be able to grok everything about the language in your head all at once... yeah I'm going with "simpler language".


I'm not dissing Golang, I use it actively, both at work and in my own projects. There's a lot to like about it.

There's also a lot to like about Haskell. Complaining about something which you don't understand isn't a good look on anyone, though.


Could you please address the tradeoff if you're going to post on the issue, and not a specific bullet point?

How do you feel about the increase in project-specific abstractions in Go? Or do you disagree with that framing?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: