0

I am trying to make a list with Points (a datatype that I created), the idea is add an element in each iteration. Something is wrong.

I have tried to put p out of myLoop but it doesn't seems to work either.

main = myLoop 
myLoop  = do 
            let p = []
            done <- isEOF
            if done
              then putStrLn ""
              else do inp <- getLine
                      let (label:coord) = words inp
                      p ++  [Point label (map getFloat coord)]
                      -- print (pointerList)
                      myLoop 

I am getting this output

trabalho.hs:30:23: error:
    • Couldn't match type ‘[]’ with ‘IO’
      Expected type: IO Point
        Actual type: [Point]
    • In a stmt of a 'do' block:
        p ++ [Point label (map getFloat coord)]
      In the expression:
        do inp <- getLine
           let (label : coord) = words inp
           p ++ [Point label (map getFloat coord)]
           myLoop
      In a stmt of a 'do' block:
        if done then
            putStrLn ""
        else
            do inp <- getLine
               let (label : coord) = ...
               p ++ [Point label (map getFloat coord)]
               ....
   |
30 |                       p ++  [Point label (map getFloat coord)]
   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • 1
    Variable in Haskell are immutable. You can't change their value during program run. Use recursion instead. – Fyodor Soikin Sep 24 '19 at 00:14
  • 3
    `p ++ […]` doesn't change `p`. It creates a new list. And because that happens in a `do` block with return type `IO`, the compiler complains that it's a list not an IO action. Give `myLoop` a list parameter, call it initially with the empty list in `main`, and append to it before passing the new list to the recursive call. – Bergi Sep 24 '19 at 00:27

1 Answers1

5

First of all, do-notation is syntactic sugar with the following rules:

do x <- mA
   mB

roughly* desugars to mA >>= \x -> do mB, where mA has type Monad m => m a and do mB has type Monad m => m b for some types m, a, and b.

do mA
   mB

desugars to mA >> do mB, where mA has type Monad m => m a and do mB has type Monad m => m b for some types m, a, and b.

do a

desugars to a.

main is a special name that represents the entrypoint of the program, and it has type IO a for some type a. Because you define main = myLoop, myLoop must also have type IO a.

Therefore, in your myLoop function:

myLoop  = do 
            let p = []
            done <- isEOF
            if done
              then putStrLn ""
              else do inp <- getLine
                      let (label:coord) = words inp
                      p ++  [Point label (map getFloat coord)]
                      -- print (pointerList)
                      myLoop 

the do-block is working with the type m = IO. Therefore, when you write p ++ [Point label (map getFloat coord)], the typechecker expects a value of type IO c, for some type c.

However, p ++ [Point label (map getFloat coord)] has type [Point], resulting in the type error Cannot match type '[]' with 'IO'.

As the type mismatch indicates, your code does not make sense. I assume that you want to append Point label (map getFloat coord) to p. ++ does not mutate p; it creates a new list! Idiomatic Haskell uses recursion to achieve what you want. The most direct way of fixing your code would be to do the following:

main = myLoop []
myLoop p = do
    done <- isEOF
    if done
    then putStrLn ""
    else do inp <- getLine 
            let (label:coord) = words inp
            let p' = p ++  [Point label (map getFloat coord)]
            myLoop  p'

Here, myLoop takes p as a parameter and recursively passes an updated p to itself after reading input. main calls myLoop with an argument of [], which is the initial value of p.

The Haskell Wikibook has a good explanation of do-notation. In general, I would recommend reading the Haskell Wikibook to better understand Haskell.

*I say "roughly" because these aren't the exact rules. The Wikibook article explains do-notation in depth.

Del
  • 1,309
  • 8
  • 21
  • after fixing it, maybe comment on how `p` isn't used at all in the end, and fixing *that*, the algorithms is quadratic. probable fixes: cons-and-reverse; using difference list (`(xs ++)`) encoding instead of plain `++`; or restructure the `do` block to non-tail-recursive, `sequence`-like structure (`getPoints =~ [ p:ps | p <- getLine, ps <- getPoints`, writing with "monad comprehensions" for brevity). – Will Ness Sep 25 '19 at 20:38