Haskell Code Formatting

Haskell has a padding style for blocks. I know two styles, but I can’t decide which style is better. (Forgive me for the really dumb example function)

1st - pretty:

funcA :: Integer -> IO () funcA n = if n == 0 then putStrLn "zero" else do putStr "--> " print n 

This style looks great, but it is very fragile: let's reorganize this code and rename funcA - we need reindent then , else and all the expressions in do . Same thing for renaming n . This is annoying. Highly.

EDIT As mentioned in FUZxxl, the strings are getting longer, but most of them are spaces at the beginning.

Another style is friendly but not very refactoring:

 funcA :: Integer -> IO () funcA n = if n == 0 then putStrLn "zero" else do putStr "zero" print n 

What style do you prefer and why? Perhaps you have another or you have a link to some great developers codestyle with explanations?

+4
source share
2 answers

Personally, I use a combination of both styles.

When the next “beautiful” indent layer is not too far away, I use the first style

 do foo bar baz 

But when a beautiful indentation leads to too long code on the right side, I use only two spaces

 case foo of a -> bar b -> baz c -> quux 

When I have an indentation greater than, say, 20 spaces, I often "reset" the indentation level:

 do a b <- do c -- normally I use only two whitespaces here d e <- do f g h 

In cases where you can put the first list from the list immediately after the keyword, I only do this if I use a beautiful style

  main = do x y z where a = b c = d e = f 

Your example

 funcA :: Integer -> IO () funcA n = if n == 0 then putStrLn "zero" else do putStr "--> " print n 

In this example, however, I would reorganize the code to use pattern matching and explicit monadic operations (in this case >> ), replacing do . If do short, do not.

 funcA :: Integer -> IO () funcA 0 = putStrLn "zero" funcA n = putStr "--> " >> print n 
+5
source

I still do not understand my "perfect" Haskell style. Currently, I usually write code, probably the most heavily dependent on coding in Python and Mercury.

It seems to me that multi-line structures have an obvious “header” line, which tells me that the structure is without a private read (usually this means that the “shape” of the multi-line structure should be determined by the beginning or end of the header line) and have different “components” of the multi-line Structures with several separate multi-line parts, clearly indicated by a change in indentation. Therefore, I would rather write your example:

 funcA :: Integer -> IO () funcA n = if n == 0 then putStrLn "zero" else do putStr "--> " print n 

Or perhaps:

 funcA :: Integer -> IO () funcA n = if n == 0 then putStrLn "zero" else do putStr "--> " print n 

with else and do stacked on the same line (although in this case I start a new line after do ). Similarly, a function whose definition is a do block usually has a do immediately after = in the function header and the actual code of the do block following the indent of the rowset.

If the if / then / else condition was more complex, I would also give its own “section”, becoming:

 funcA :: Integer -> IO () funcA n = if n == 0 then putStrLn "zero" else do putStr "--> " print n 

I am sure that this if / then / else format depends on a relatively recent change in GHC; the earlier part of then and else should have been indented more than if . I never found a way to write if / then / else blocks, which was very comfortable with this rule; fortunately, they are not very common in Haskell due to pattern matching and security.

There are some inconsistencies in the way I use this style, which is not yet satisfied. For example, in the file that I am currently opening, I have several form functions:

 foo ab = simple expression cd where c = bar a d = baz b 

Which looks good, but then:

 foo ab = complex multiline expression cd where c = bar a d = baz b 

where should logically be at a different level of indentation from the main body of the function. But it should not be indented anymore, because it is part of foo ab = , and not part of complex ... But I also don’t want to indent complex ... one level more, because going to two levels of indentation looks ugly, and this is unpleasant for its correct level of indentation, determined by whether there is a where block afterwards. Fortunately, I mostly use where , when a function definition is a simple expression of some helper definitions; if a function arises as a big complex function of some auxiliary definitions, I try to break it down into more independent parts.

I feel that this style basically avoids indentation from running away (it also “reorganizes” in terms that do not determine the correct position of the indentation in the code by the length of the other bits of the code), but at the same time allowing me to visually define the high-level structure of my code without doing low level structure analysis.

Sometimes it seems to me that I think too much, like Pythonista (with indentation levels) or Mercuryista (?) (With code structures that have sections), instead of accepting Haskell's "indentation" more than the position at which they started "an approach". But as things start to get complicated, things like your first nice example become clearly incomprehensible and unreadable to my taste.

+1
source

All Articles