1

Can I use if syntax in a where block? In the following, the if in the second where block where second is defined yields a parse error and I can't figure it out.

data Label = A | B | C deriving (Show)
type Path = ([(Label, Int)],Int)
data Section = Section { getA :: Int, getB :: Int, getC :: Int } deriving (Show)

getPath :: Section -> (Path, Path)  -> (Path, Path)
getPath () (Section a b c) = go
    where 
        go ((toppath,top),(bottompath,bottom))
            |top<c+bottom = ((A,a):toppath,top+a, second)
            |otherwise = ((A,a):(C,c):bottompath,bottom+c+a, second)
                where second =
                    if (bottom<c+top)
                        then ((B,b):bottompath,bottom+a)
                        else ((A,b):(C:c):toppath,top+c+a)
squirrels
  • 303
  • 1
  • 11
  • As an aside, `()` is not valid for either an argument of type `Section` or an argument of type `(Path, Path)`. – chepner Oct 21 '20 at 18:24
  • As a beginner I found it was generally easier to avoid indentation errors by *always* putting a newline+indent after a layout keyword (`where`, `do`, `let`, `of`) instead of having to worry about alignment at all. Here, that would just mean putting a line break between `where` and `second` and indenting accordingly. Alternatively, you can always use explicit `{}` blocks and `;` separators, but (imo unfortunately) there’s no option to make them required. – Jon Purdy Oct 21 '20 at 21:07

1 Answers1

1

You can, but you should indent the if in the scope of the where, so:

getPath :: Section -> (Path, Path)  -> (Path, Path)
getPath () (Section a b c) = go
    where 
        go ((toppath,top),(bottompath,bottom))
            |top<c+bottom = ((A,a):toppath,top+a, second)
            |otherwise = ((A,a):(C,c):bottompath,bottom+c+a, second)
                where second =
                       if (bottom<c+top)  -- &leftarrow; extra indentation
                        then ((B,b):bottompath,bottom+a)
                        else ((A,b):(C:c):toppath,top+c+a)

There are however some type errors, for example:

  • () is the data constructor of the unit type, but not a Section, so you should remove () in getPath () (Section a b c) = …;
  • you construct 3-tuples with ((A,a):toppath, top+a, second); and
  • the C in in (C : c) is a Label, not a Path, so that will also error.

You will thus need to fix some problems in the code.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Thanks I hadn't noticed those yet haha. Why do I have to indent the if twice? I don't see any alignment going on. – squirrels Oct 21 '20 at 18:43
  • The `if` must be more indented than the end of the `where` – Sir4ur0n Oct 21 '20 at 19:47
  • @squirrels You might want to read a short [summary of the indentation rules](https://stackoverflow.com/questions/33004521/what-indentation-is-required-for-a-case-statement-within-a-let-statement/33010779#33010779). – chi Oct 21 '20 at 20:03
  • 1
    @Sir4ur0n More than that, right? It must be indented beyond the first character of the name it is defining. – amalloy Oct 21 '20 at 21:02