Christopher L Conway wrote:
I've installed 2.3 and it exhibits the same indentation behavior: any
entity appearing on a new line immediately after "module X where"
wants to be indented 4 spaces, including function definitions and
variable bindings.

Yes, it does do that. And it's correct syntax too. But I tend to override it by putting the first line flush-left. After that, it knows.


"if-then-else" want to be lined up with one
another, although both GHC and Hugs reject this layout.


I'll leave that issue for now, it's fiddly. I thought it was fixed in recent GHCs, but it's not something haskell-mode has ever got right.

Here's the result of indent-region on the prior example:

No! No!

You can't use indent-region on haskell code. Why not? Because indentation involves *semantic* choices! And how can haskell-mode possibly guess the semantics of your code?

indent-region just chooses the 'first choice' in the fairly arbitrary list of choices for each line, I think. You could argue that it could have better heuristics, and guess better more often. Alternatively (and perhaps this makes more sense) you could argue that indent-region should never change the semantics; rather it should just normalise the indentation. I.e. it should be merely a pretty-printer.


module Num where

   import IO

       main = do
            putStrLn "Enter a number: "
                     inp <- getLine
                            let n = read inp
                                    if n == 0
                                    then putStrLn "Zero"
                                    else putStrLn "NotZero"

This is distressing, because I've gotten rather used to letting Emacs
worry about indentation for me. (This works well in tuareg-mode for
OCaml. But, as I said earlier, I am a layout-sensitive-language
newbie.)

You need to get used to hitting <tab> until you see the indentation you want. There are choices to make and emacs can't make them (all) for you.

For example, consider the fragment after the 'let'.

What you have written is equivalent to this:

let n = read inp (if n == 0 then putStrLn "Zero" "NotZero")

I.e. you are treating read as a two-argument function, and the second argument is the entire if expression.



Haskell layout is really quite simple, when you get used to it. The problem is it's not that easy to explain to someone from an imperative background; because you have to cross two bridges at once - the 'imperative' bridge and the 'layout' bridge.

Layout isn't active 'everywhere' in haskell. In fact, arguably, it isn't even active in 'most' haskell. The two contexts in which layout mode applies most often are do expressions and declarations. Declarations is 'mostly' the top level of the file (it also applies if you define more than one name in a let or a where, but that's a relatively advanced technique). Do expressions are introduced by 'do' as you can see.

I urge you to experiment more in the REPL (ghci/hugs) and less with loading files, and find lots of examples on the web, and hopefully this will all become clear.

Jules
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to