How to replace "let/in" construction with "where" in IO () function in Haskell?

Viewed 123

I am studying Haskell and trying my first IO functions. Here a simple program that calculates the area of a rectangle, it works fine:

squareCalc :: IO ()
squareCalc = do
  putStrLn "Pease enter the lenght"
  length <- getLine
  putStrLn "Pleas enter the width"
  width <- getLine
  let square = read length * read width
   in putStrLn ("The square is " ++ show square)

However, when I try to replace "let/in" with "where":

squareCalc2 :: IO ()
squareCalc2 = do
  putStrLn "Pease enter the lenght"
  length <- getLine
  putStrLn "Pleas enter the width"
  width <- getLine
  putStrLn ("The square is " ++ show square) 
    where
       square = (read length) * (read width)

the compiler returns an error error:

Variable not in scope: width :: String

I am wondering if there ever possible to use "where" in functions like this?

2 Answers

The way you indented

putStrLn ("The square is " ++ show square) 
  where
     square = (read length) * (read width)

makes me think that you want this code to be treated as an expression. The problem is that where isn't legal in expressions. It's only legal after the right hand side of a variable/function/pattern binding.

You might expect to just get a syntax error then, but that isn't how the layout rule works. When the parser encounters a syntax error, and there is an open implicitly-curly-bracketed block from the layout rule, it will close that block to try to make the error disappear. In this case, it works: your code becomes

squareCalc2 = do
  { ... }
    where
       square = (read length) * (read width)

which is syntactically valid. But length and width are only in scope inside the curly brackets, so compilation fails anyway.

Note that let without in is allowed in do blocks as a convenience, so you can write this:

squareCalc = do
  ...
  let square = read length * read width
  putStrLn ("The square is " ++ show square)

Nope, it's not possible. Annoying. The closest you can get is to make the thing in the where block be a function.

squareCalc2 = do
    ...
    putStrLn ("The square is " ++ show (square length width))
    where square length width = read length * read width
Related