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

I wrote Haskell for a couple years and I _never_ figured out the indentation rules. The haskell people seemed confused that it was even possible to find it confusing

and then there’s “do” notation. I has three people tell me “it’s just a simple mechanical transformation from lambdas” oh yeah? how? they couldn’t explain that either



    mySubroutine = do
      foo <- mkFoo
      bar <- mkbar foo
      mkBaz bar
    
    mySubroutineV2 =
      mkFoo >>= \foo ->
        mkBar foo >>= \bar ->
          mkBaz bar


Note that this is same desugaring for normal let

  let x = y in F   <===>   (\x.F)(y)
just replacing function application with a different function (>>=).


This is not the case in Haskell, because let-bindings can be self-referential, while lambdas cannot (without using a fixed point combinator). Also, in most functional languages, a let-binding causes type generalisation, which is not the case for a lambda.


Not exactly the same: `x` is given a polymorphic type (in F) in Haskell (restricted to values in ML) whereas the unannotated let-over-lambda will give `x`a monomorphic type.


You can desugar let bindings that way but often times (as I believe is the case in GHC) you have a `Let` term in your AST.


I'll agree about the weird Haskell indentation rules.

But do notation really is just syntactic sugar for a chain of >> and >>= applications (plus "fail" for invalid pattern matches). It's not usually pretty or understandable to write it that way, but it's a very simple translation. If the people you talked to couldn't explain it to you, I think they maybe didn't understand it well themselves.


The reason people can’t remember it on the spot is that it’s really not necessary to understand how do-notation desugars in order to use it.

People usually check it once, see that it is correct and forget about it.


Do-notation is not all that different—if anything, it is simpler—than async/await syntax that's gotten popular in a bunch of mainstream languages. I don't know if that makes it easy or difficult in an absolute sense, but it isn't any worse than Python/JavaScript/etc.

The indentation rules are definitely a mess though :/


To understand "do" you need to understand the underlying >>= and return operators for your monad.

If you can use >>= and return to do it then "do" is indeed a mechanical transformation.

It is like await if you understand JS promises.


> and then there’s “do” notation. I has three people tell me “it’s just a simple mechanical transformation from lambdas” oh yeah? how? they couldn’t explain that either

Scala's for/yield (which is pretty similar) you can literally do an IDE action in IntelliJ to desugar it.

I forget the precise Haskell syntax, but do {a <- x; b <- y; c <- z; w } is sugar for something like x >>= $ \a y >>= $ \b z >>= $ \c w . Hopefully the pattern is clear. Were there cases where you actually couldn't see how to desugar something, or are you just nitpicking about them calling it a mechanical transformation without being to explain the precise rules?


I wrote a tutorial about do notation. Maybe it helps https://elbear.com/a-user-guide-for-haskell-monads


> I _never_ figured out the indentation rules

I'm glad I'm not the only one. The white-space as syntax in some cases is very confusing. It took me a while to figure it out.


It is the same as in any ML derived language, or Python.

I also don't see the issue, when there is tooling that complains about broken indentation.


> I _never_ figured out the indentation rules

Weird. Haskell's my preferred language and I thought there was only one indentation rule - if something's further to the right it's part of the same expression, and if something's down it's a new expression.

  f
   x
    y
  g z
... With a slight addendum that you don't need to write 'let' on consecutive lines, e.g.

  let x = ...
      y = ...




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

Search: