Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Couldn't match type `Stack' with `IO'

Tags:

io

haskell

this is my first time to use Haskell and i have read many many tutorials about it. But when it came to practice, many problems show up. I m trying to make a stack data structure and use it in the Do block. But when i do this. It says cant match type'Stack' with 'IO', i have no idea about this problem. Following is my code:

import Data.Array.IO

main::IO()
main = do
     arr <- newArray((0,0),(8,13)) 0 ::IO (IOArray(Int,Int) Int) 
     list <- getElems arr
     print list
     push 0 mystack   --here is the problem
     return()

data Stack a = Stack [a] deriving Show

empty :: Stack a
empty = Stack []

push :: a -> Stack a -> Stack a 
push x (Stack xs)= Stack (x:xs)

pop :: Stack a -> (Maybe a, Stack a)
pop (Stack []) = (Nothing, Stack [])
pop (Stack (x:xs)) = (Just x, Stack xs)

mystack = empty

Problem is below(when i put push 0 mystack in the Do block it shows up)

Couldn't match type `Stack' with `IO'
    Expected type: IO Integer
      Actual type: Stack Integer
    In the return type of a call of `push'
    In a stmt of a 'do' block: push 0 mystack
like image 674
user3889372 Avatar asked Mar 16 '26 15:03

user3889372


2 Answers

The problem here is that main has type IO (), meaning that any statement inside the do block must have type IO a for some type a. Your data type is Stack a, which does not match IO a. You also look like you're wanting some sort of "mutable state" with your stack, but all your functions are pure, meaning they simply return a new value. Values in Haskell are immutable, meaning that they can't be modified after being declared. For most purposes, Haskell doesn't have variables, just named values.

What you probably really want is to use the State monad. You could modify your push and pop functions to work in that monad instead, and then use execState to run the stateful computation:

import Control.Monad.State

data Stack a = Stack [a] deriving (Eq, Show)

push' :: a -> Stack a -> Stack a
push' x (Stack xs) = Stack (x:xs)

push :: a -> State (Stack a) ()
push x = modify (push' x)

pop' :: Stack a -> (Maybe a, Stack a)
pop' (Stack []) = (Nothing, Stack [])
pop' (Stack (x:xs)) = (Just x, Stack xs)

pop :: State (Stack a) (Maybe a)
pop = state pop'

Notice how easy it was to directly use your already written functions to implement this! You even had pop return the Maybe a in the first element of the tuple to go straight into the state function. You can then use this as

main :: IO ()
main = do
    let resultStack = flip execState empty $ do
            push 1
            push 2
            push 3
            pop                    -- pop off 3
            Just x <- pop          -- pop off 2
            push $ 2 * x           -- push 4
            mapM_ push [1..10]     -- Pushes 1 through 10 onto the stack in that order
            pop                    -- pop off 10
            pop                    -- pop off 9
            pop                    -- pop off 8
    print resultStack

This will print out

Stack [7, 6, 5, 4, 3, 2, 1, 4, 1]
like image 170
bheklilr Avatar answered Mar 20 '26 00:03

bheklilr


push 0 mystack returns a new stack. You are not getting the return value, and you are writing this line as an "action". "Actions" are things that change the global state of the system, they are marked by functions returning IO. Since push doesn't change the global state, haskell tells you that there's no reason to call it like you do.

What you probably mean is:

let newStack = push 0 mystack
like image 23
tohava Avatar answered Mar 19 '26 22:03

tohava