Hacker News new | ask | show | jobs
by dmitriid 3247 days ago
Short version: You need a PhD in type theory to get anywhere.

Basically every obscure overly complicated concept that Haskell throws at you (all the while pretending to be the only true FP language out there) can be explained in 5 to 10 lines of Javascript: https://github.com/hemanth/functional-programming-jargon

Compare and contrast.

- Monad explained in Javascript: https://github.com/hemanth/functional-programming-jargon#mon...

- Timeline (sic!) of monad tutorials for Haskell: https://wiki.haskell.org/Monad_tutorials_timeline

The worst crime against humanity though is Haskell crap seeping into other languages (such as ramda, for instance: http://ramdajs.com)

3 comments

> You need a PhD in type theory to get anywhere.

That is extremely false. Haskell isn't even a good playground for academic type theory -- you'd want Agda etc. for that. The development of the language over the last few years has been characterized by pragmatism and a focus on backwards-compatibility, which is why you can take code from something like ten years ago and have it run without issues on modern versions of the Haskell compiler with little to no modifications. (Let's not talk about how long code written in "modern" JS lasts.)

And I'd really like to see type class constraint resolution with functional dependencies, or Hindley-Milner type checking, or something of that sort implemented in "5-10 lines" of JS.

"There he goes again with his mumbo-jumbo," you say. That's right, you don't need to care about those things to write Haskell. What you meant is implementations of typeclasses ("interfaces") like Monad, Functor, and so on: they don't take much more code in Haskell.

  Array.prototype.chain = function (f) {
    return this.reduce((acc, it) => acc.concat(f(it)), [])
  }

  instance Monad [] where
    xs >>= f = concat (map f xs)
    return = pure
And we didn't even have to go the "this" route! Notice that your 5 - 10 lines of JS don't let you write code that works in any monad, whereas I can easily write

  whenM :: Monad m => m Bool -> m () -> m ()
  whenM cond action = do
    condition <- cond
    if cond then action else pure ()
In Elm, you'd have List.whenM, Array.whenM, Maybe.whenM, ... or a straight-up false type signature like their Eq ones, and in JS, a bunch of prototype methods with no unifying threads.

--

As for an example of why I think Haskell has the right ideas (few of us will say it's the "best language evar"):

I'd really like to see a JS version of the Servant library, which takes an API spec for a server and actually generates a fully functional server from that. Here's a description:

https://news.ycombinator.com/item?id=14149200

Does this strike you as idle theoretical self-enjoyment?

> This is extremely false [referring to "You need a PhD in type theory to get anywhere."]

almost immediately followed by

> And I'd really like to see type class constraint resolution, or Hindley-Milner type checking

You don't even see the irony in that, do you?

> they don't take much more code in Haskell:

riiight. I won't even go into the number of things that need to be explained there before you even start explaining what the code does.

I hadn't really finished editing my comment then. (I was eating at the time, haha.) I just saw your reply now.
So, you could say your comment was ... lazy?

(huehuehue, lame joke, I know :) )

Commenting on the edited comment :)

> Notice that your 5 - 10 lines of JS don't let you write code that works in any monad, whereas I can easily write

Maybe, maybe not. Depends on your requirements, really. The core language might never get this, but these 5-10 lines of code do some very important things:

- they explain monads faster and clearer than any of the countless monad tutorials that exist for Haskell

- they demystify monads and show that: hey, you've probably been writing monads all along (and re-implemented them yourself countless of times, no doubt)

- they (by necessity) dumb down the jargon-heavy lingo for easy consumption by average Joes like me :)

Edit: that page in particular has also shown me that I have used easily half of Haskell's things (functors of all flavors, monads, comonads, etc. etc. etc.) countless times over the years in Javascript and Erlang. I didn't even know I did, because no one scared me off with the theory, and strange explanations and names :)

Is it fair to say that your argument here is that "this resource was extremely valuable to me for understanding certain concepts in ways that Haskell-oriented resources in the past have not been"?

I think that's a totally fair criticism. I also believe that the Haskell resources can provide further value to you (and others in your position) over time if you choose to study them. Similarly, studying category theory or type theory or logic could.

Are these practical things to do? It depends upon your goals.

Sure! I don't disagree: Haskell learning materials are a far cry from adequate, and we definitely need to learn from, e.g. the Rust/Elixir/Elm communities here. For now, this is worth trying:

http://haskellbook.com/

Also, #haskell on IRC has been, without a doubt, one of the friendliest learning environments I've ever seen. Drop by sometime if the mood strikes you. :)

This is not really a definition of a Monad. For example, there's no mention of the Monad laws.

Monads are a very general and powerful abstraction that are not adequately described by your example. My advice to anyone is to read Phil Wadler's seminal paper, it is very easy to read.

> Does this strike you as idle theoretical self-enjoyment?

It does.

How many PhDs does one require to understand/correct/debug all the :> and :<|> etc.?

Speaking from experience, zero.

> debug

But the whole point of a good compiler is that it tells you when you're wrong! (Instead of having to write hundreds of tests (and thousands of Node test runners).)

> :> and :<|>

You can just treat them as syntax, like the largest proportion of every other language, but with the opportunity of actually being able to write things like that yourself later.

Observe:

    type API = "polls"                                           :> Get  '[JSON] [Poll]
          :<|> "polls" :> Capture "question_id" Int              :> Get  '[JSON]  Poll
          :<|> "polls" :> Capture "question_id" Int :> "results" :> Get  '[JSON]  PollResults

The :> operator separates parts of a path, and the :<|> separates different URL patterns. This is the equivalent of this API from the Django documentation:

    urlpatterns = [
        # ex: /polls/
        url(r'^$', views.index, name='index'),
        # ex: /polls/5/
        url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
        # ex: /polls/5/results/
        url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results')
    ]
The only difference is it has less regexes in it, is capable of being checked for nonsense by a compiler much smarter than me, and gives you the aforementioned "server for free". I have had URL pattern-match errors with Django in the past, and having your compiler check that there aren't any is excellent.

Easier to maintain? Check.

Easier to read? Check. (If nothing, because of the lack of regexes.)

Defines the response type too? Check.

Easy to refactor? Check! Tired of typing "polls" at the beginning? Just lift it out: turn

    type API = "polls"                                           :> Get  '[JSON] [Poll]
          :<|> "polls" :> Capture "question_id" Int              :> Get  '[JSON]  Poll
          :<|> "polls" :> Capture "question_id" Int :> "results" :> Get  '[JSON]  PollResults
into

    type API = "polls" :> 
             (                                            Get  '[JSON] [Poll]
          :<|>  Capture "question_id" Int              :> Get  '[JSON]  Poll
          :<|>  Capture "question_id" Int :> "results" :> Get  '[JSON]  PollResults
             )
Types are first-class :)

> How many PhDs does one require to understand/correct/debug all the :> and :<|> etc.?

Definitely less than it takes to become comfortable with the quirks of literally everything in JS: perhaps you should give something an honest shot before telling people who have derived real-world benefits from using it in production that it's useless?

> Speaking from experience, zero. You can just treat them as syntax, like the largest proportion of every other language, but with the opportunity of actually being able to write things like that yourself later.

So, basically, "learn this thing without understanding what it does" :-\

Reminds me of teaching Java to newbies: "oh, just type this syntax, you have to memorize it, don't worry about it".

> Definitely less than it takes to become comfortable with the quirks of literally everything in JS: perhaps you should give something an honest shot before telling people who have derived real-world benefits from using it in production that it's useless?

A real app is not just "hey, memorize this DSL and type it". I've found Haskell unapproachable on multiple occasions. And yes, I've completed my obligatory "Haskell from first principles" and "Learn You a Haskell for Great Good!" :)

Well, Servant isn't introductory Haskell material. My point was to show that the advanced type system features of modern Haskell are useful in the real world, for, e.g. building webapps that real people use and ship to production.

If you've picked up the stuff in LYAH, you're ready to learn what type operators are (that's where :> and friends come from, they're just things like Maybe but written infix, so they're probably defined as

data a :> b = ColonPointyThing a b

or something like that.) Servant then pattern-matches on these types, essentially. For instance, if I can handle an API that serves endpoint A, and one that serves endpoint B, I can handle an API that serves both:

    instance (Handler A, Handler B) => Handler (A :<|> B) where

       handle req = ...
That's the idea.

You'd hardly expect a beginner to pick up, I dunno, using React and Redux on a Webpack hot-reloadable setup on day 1 of "Javascript 101", but React is one of the best ways to sell modern web development (at least when I've been buying).

The problem is basically how to arrive at the "same level" in Haskell and in JS.

Basically: what does it take to define (or even to just understand) a type-level DSL in Haskell, and a sufficiently advanced library in Javascript.

I can take apart almost any JS library and see/understand how it works. How much type-foo do I need to understand Servant? Or any other sufficiently complex Haskell library (a friend of mine has struggled mightily with Yesod and gave up after a month or so).

>> Speaking from experience, zero. You can just treat them as syntax, like the largest proportion of every other language, but with the opportunity of actually being able to write things like that yourself later.

> So, basically, "learn this thing without understanding what it does" :-\

> Reminds me of teaching Java to newbies: "oh, just type this syntax, you have to memorize it, don't worry about it".

I don't think what's recommended is the same.

Let's consider this quote:

--- start quote ---

> :> and :<|> You can just treat them as syntax, like the largest proportion of every other language, but with the opportunity of actually being able to write things like that yourself later.

--- end quote ---

This is exactly what's recommended: just blindly type these things, your understanding is not required.

It becomes worse. Link: https://news.ycombinator.com/item?id=14890937

You need 10 language extensions to implement the simples things. Answer to that complain?

Oh, five of them are just workarounds [so, just blindly copy-paste them]

You certainly would need a PhD to fully understand Monads from that small JavaScript snippet. The Haskell link you gave gives Phil Wadler's original paper as the first link. It is easy to read, explains everything beautifully and full of many examples. Learn some basic Haskell for no other reason than to read seminal papers such as these. To favour some random JavaScript hacker on the internet and steer others away from the original work is anti-intellectualism.
Ah, here comes the condescending tone I've so come to appreciate from the Haskell programmers.

"Go and read", "anti-intellectualism".

Wadler's paper is an excellent piece of exposition that's us at the level of an upper-year undergraduate textbook. There's nothing condescending about referring a professional to a relevant paper in their discipline, but it is troubling when a professional won't even read over a paper.
It's troubling when people assume there's only one paper that a professional should read. Or that a professional cannot choose between papers to read. etc.
How did anyone imply this? A single free, reputable resource was offered, but many more exist.
You are misquoting me. I said steering others away from the original source of work to an interior source (incomplete at best) is anti-intellectualism.

I do not mean to be condescending, but I feel very strongly about this.

In order not to copy-paste, I'll link to my reply in another thread: https://news.ycombinator.com/item?id=14890766
Wait... you're tone policing haskell users after referring to even the _adaptation_ of functional techniques as a "crime against humanity?"

Please rethink this approach. It is a bad approach. It fails to capture (what I think you) your argument (is) and antagonizes people needlessly. And quite frankly, a lot of people are being VERY nice by not following in the tradition of absolutely burying javascript for its nonsensical primitive type semantics.

> Basically every obscure overly complicated concept that Haskell throws at you (all the while pretending to be the only true FP language out there) can be explained in 5 to 10 lines of JavaScript

So presumably the same concepts can be explained in 5 to 10 lines of Haskell too.

I think you're confusing the refinement and polishing of ideas that's taken place in Haskell over the last two decades with the succinct presentation of those ideas once they've been worked out.

But they can't, can they. Or we wouldn't have the bazillion monad tutorials.

The funny thing, this is the trouble that plagues other Haskell-inspired work (such as Purescript)

It's obvious that the concept of monad can either be explained in 5-10 lines in both JavaScript and Haskell, or neither. Which are you claiming?
It's not obvious.

I'm claiming that:

- the concept of monad can be explained in 5-10 lines in Javascript (demonstrable)

- the concept of a monad requires multiple years and tens of tutorials in Haskell (also demonstrable)

I just want to reiterate: point 1 is totally false. That description you linked is incredibly incorrect, captures almost nothing of the spirit of what a monad is, and is somewhat disingenuous.

Lots of people get excited about "monads" and then rush out to write tutorials to try and capture whatever mental model they're using. These mental models may arrive at correct results most of the time, but they're often not really transferrable to another human.

Learn You A Haskell takes a different approach, in which you arrive at creating monads because you naturally derive them as a way to deal with the tedium of functional code w/out such mechanisms.

"Monad tutorials" are becoming much less frequent now that such approaches are offered. Everyone just says, "Go read this chapter or two of this freely available book and you're good to go."

You know, just like any major feature in javascript.

Demonstrate a pair of tutorials aimed at the same level of reader, one in JS, and one in Haskell, where you end up with a better understanding of the idea of a monad reading the former (as opposed to the implementation of the Monad instance for a list).
TIL there's some "idea of a monad".

Basically this is (in my mind) what's wrong with Haskell: it's overly concerned with the Platonic ideal.

Meanwhile that one page on jargon has shown me that I effortlessly implement any and all of those things daily (and understanding what I'm doing) without the need to understand "an idea". I just use the tool that solves the problem. If someone insists on calling this "monadic composition", or "lifting over typeclasses", or "zygohistomorphic prepromorphisms", so be it.