Reputation: 247
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
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.
in do
at the end of your block was redundant, so I removed it (alternatively, just indenting it would have worked too).Upvotes: 5
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
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