Iguana
Iguana

Reputation: 247

The last statement in a 'do' construct must be an expression : is there any indentation error

import Data.ByteString as B
import Data.ByteString.Internal as I
import Data.Bits
main = do input <- getLine
      let bs = B.pack input
      let intermediatebs  =  unfoldrN ((B.length bs)*2) unfld 0
      where unfld i
      |Prelude.rem i 2 == 0 = Just (top4 $ B.index bs (i/2) , i+1)
      |otherwise =  Just (bottom4 $ B.index bs (i/2) , i+1)
      top4bits x = shiftR x 4
      bottom4bits x = x .&. 0x0F
      top4 x = convertASCIIword8 $ top4bits x
      bottom4 x = convertASCIIword8 $ bottom4bits x
      convertASCIIword8 x
      |x <= 9 = I.c2w '0' + x
      |otherwise = I.c2w 'A' + (x-10)
      let outputbs = B.map I.w2c $ intermediatebs
      in do putStrLn (outputbs)

i am getting this compilation error The last statement in a 'do' construct must be an expression: let intermediatebs = unfoldrN ((B.length bs) * 2) unfld 0

Upvotes: 3

Views: 1264

Answers (3)

Ben Millwood
Ben Millwood

Reputation: 6991

It's hard to see exactly what you want here. It is possible to make your code parse with only indentation changes:

import Data.ByteString as B
import Data.ByteString.Internal as I
import Data.Bits
main = do
  input <- getLine
  let bs = B.pack input
  let intermediatebs  =  unfoldrN ((B.length bs)*2) unfld 0
       where
        unfld i
          | Prelude.rem i 2 == 0 = Just (top4 $ B.index bs (i/2) , i+1)
          | otherwise =  Just (bottom4 $ B.index bs (i/2) , i+1)
        top4bits x = shiftR x 4
        bottom4bits x = x .&. 0x0F
        top4 x = convertASCIIword8 $ top4bits x
        bottom4 x = convertASCIIword8 $ bottom4bits x
        convertASCIIword8 x
          | x <= 9 = I.c2w '0' + x
          | otherwise = I.c2w 'A' + (x-10)
  let outputbs = B.map I.w2c $ intermediatebs
  putStrLn (outputbs)

although it won't compile due to ambiguous getLine and putStrLn occurrences. You may want to import qualified where appropriate. Key observations:

  • Do-blocks, let-blocks etc. start from the left edge of the first thing inside them, regardless of where the keyword is itself. E.g.

    do x
       y
    -- ^ because of where the x is, all future lines have to line up with it
    
    let x = ...
        y = ...
    -- ^ if you have code appearing left of here, the let-block ends
    

    As a consequence, I often give do and where their own line before starting a block. In the example I gave above, you can see that even if I moved the do-block into a function with a longer or shorter name, the indentation wouldn't change.

  • Lines in the same block that start indented are a continuation of the previous line. Guards are a continuation so need to be indented, likewise where for a let assignment needs to be indented further than the assignment itself.

  • The in do at the end of your block was redundant, so I removed it (alternatively, just indenting it would have worked too).

Upvotes: 5

Ingo
Ingo

Reputation: 36329

Your outer do consists only of input <- getLine since the following token let is already less indended than input (which makes no sense anyway, but ....)

Perhaps you mean:

do  input <- getLine
    let ....
    let .....   where 
          unfld ....

But one can only guess. Use indendation to make clear what items belong together, and what items are subitems of others. The style above rather obscures this. Also, you shouldn't write

foo x y z
| ..... = 

because the compiler would see

foo x y z; | ... = 

Upvotes: 1

sepp2k
sepp2k

Reputation: 370082

The error message is not caused by an indentation error so much as an ordering error. You seem to have inserted the where-block in the middle of your do-block. That does not work. The entire do-block, including the final expression, should come before the where block.

That said, you do have indentation error in your definitions inside your where-block: you need to indent the pattern guards.

Upvotes: 1

Related Questions