Home > Software engineering >  Why does function expect IO[ data ] instead of [[ data ]] Haskell
Why does function expect IO[ data ] instead of [[ data ]] Haskell

Time:11-18

The following code fails with this error.

main.hs:30:13: error:
    • Couldn't match type: [[Octopus]]
                     with: IO a0
      Expected: IO a0 -> IO a0
        Actual: [[Octopus]] -> [[Octopus]]
    • In the first argument of ‘iterate’, namely ‘loopStage’
      In the first argument of ‘(!!)’, namely
        ‘iterate loopStage octopusMatrix’
      In a stmt of a 'do' block: iterate loopStage octopusMatrix !! 100
   |
30 |     iterate loopStage octopusMatrix !! 100
   |   
module Main where


data Octopus = Octopus {
    level :: Int,
    hasFlashed :: Int
} deriving (Show)


incrementOctopusEnergyLevelByOne :: Octopus -> Octopus
incrementOctopusEnergyLevelByOne (Octopus level hasFlashed) = 
    Octopus (level   1) hasFlashed

incrementOctopusListEnergyLevelByOne :: [Octopus] -> [Octopus]
incrementOctopusListEnergyLevelByOne = map incrementOctopusEnergyLevelByOne

increaseAllEnergyLevel :: [[Octopus]] -> [[Octopus]]
increaseAllEnergyLevel = map incrementOctopusListEnergyLevelByOne

loopStage :: [[Octopus]] -> [[Octopus]]
loopStage octopus_matrix = do
    increaseAllEnergyLevel octopus_matrix

main = do  
    contents <- readFile "input.txt"
    let fileLines = lines contents
    let matrix = parseListOfStringsToMatrixOfIntegers fileLines
    let octopusMatrix = convertMatrixToOctopusMatrix matrix
    
    iterate loopStage octopusMatrix !! 100
    
    print octopusMatrix

parseStringToListOfIntegers :: String -> [Int]
parseStringToListOfIntegers string = map (read . (:"")) string :: [Int]

parseListOfStringsToMatrixOfIntegers :: [String] -> [[Int]]
parseListOfStringsToMatrixOfIntegers = map parseStringToListOfIntegers

convertIntToOctopus :: Int -> Octopus
convertIntToOctopus value = Octopus value 0 

convertListOfIntsToListOctopus :: [Int] -> [Octopus]
convertListOfIntsToListOctopus = map convertIntToOctopus

convertMatrixToOctopusMatrix :: [[Int]] -> [[Octopus]]
convertMatrixToOctopusMatrix = map convertListOfIntsToListOctopus 

My question is, why does the loopStage function expect an IO value? It is clearly marked as [[Octopus]].

I tried removing the iterate, which makes the error message more defined.

main.hs:30:5: error:
    • Couldn't match type ‘[]’ with ‘IO’
      Expected: IO [Octopus]
        Actual: [[Octopus]]

After further debugging, it seems like the error is on the return type of the functions, that it is returning a non IO'able version of [[Octopus]] matrix? This is my first time writing Haskell. I tried wrapping all the return values in IO, but couldn't find a solution

CodePudding user response:

My question is, why does the loopStage function expect an IO value? It is clearly marked as [[Octopus]].

Indeed the loopStage function does not expects IO. The issue is elsewhere.

Let's focus on these lines.

    contents <- readFile "input.txt"
    -- ...        
    iterate loopStage octopusMatrix !! 100

In this do block, readFile returns a value inside IO. Therefore, Haskell infers that iterate loopStage octopusMatrix !! 100 must have type IO something.

Now, let's look at the iterate polymorphic type:

iterate :: (a -> a) -> a -> [a]

The result type of

iterate loopStage octopusMatrix !! 100

must then be a (the element type of [a], which is returned by `iterate). Therefore, we must have

iterate loopStage octopusMatrix !! 100 :: a
loopStage :: (a -> a)
octopusMatrix :: a
a = IO something

Hence, we expect

loopStage :: IO something -> IO something

which copes with the actual type of loopStage:

loopStage :: [[Octopus]] -> [[Octopus]]

Note that the GHC error message is saying exactly this:

Expected: IO a0 -> IO a0
Actual:   [[Octopus]] -> [[Octopus]]

This means "You are trying to pass loopStage which has type [[Octopus]] -> [[Octopus]] to a function (iterate) which instead expects a type of the form IO a0 -> IO a0".

How to fix this? One has to avoid trying to "run" the result of iterate as if it were an IO action:

let newOctopusMatrix = iterate loopStage octopusMatrix !! 100
print newOctopusMatrix
  • Related