Haskell无法将类型`Stack'与`IO'匹配

use*_*372 2 io haskell

这是我第一次使用Haskell,我已经阅读了很多关于它的教程.但是在实践中,出现了许多问题.我试图建立一个堆栈数据结构并在Do块中使用它.但是当我这样做的时候.它说不能匹配类型'堆'与'IO',我不知道这个问题.以下是我的代码:

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
Run Code Online (Sandbox Code Playgroud)

问题在下面(当我把推出0 mystack放在它显示的Do块中时)

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
Run Code Online (Sandbox Code Playgroud)

bhe*_*ilr 5

这里的问题是main具有类型IO (),这意味着do块内的任何语句必须具有IO a某种类型的类型a.您的数据类型Stack a不匹配IO a.你也看起来像是想要你的堆栈的某种"可变状态",但你所有的功能都是纯粹的,这意味着它们只返回一个新值.Haskell中的值是不可变的,这意味着它们在声明后不能被修改.在大多数情况下,Haskell没有变量,只有命名值.

你真正想要的是使用Statemonad.您可以修改您的pushpop函数以在该monad中工作,然后用于execState运行有状态计算:

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'
Run Code Online (Sandbox Code Playgroud)

请注意直接使用已编写的函数来实现它是多么容易!你甚至已经在元组的第一个元素中pop返回Maybe a直接进入state函数.然后你可以用它作为

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
Run Code Online (Sandbox Code Playgroud)

这将打印出来

Stack [7, 6, 5, 4, 3, 2, 1, 4, 1]
Run Code Online (Sandbox Code Playgroud)