这是我第一次使用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)
这里的问题是main具有类型IO (),这意味着do块内的任何语句必须具有IO a某种类型的类型a.您的数据类型Stack a不匹配IO a.你也看起来像是想要你的堆栈的某种"可变状态",但你所有的功能都是纯粹的,这意味着它们只返回一个新值.Haskell中的值是不可变的,这意味着它们在声明后不能被修改.在大多数情况下,Haskell没有变量,只有命名值.
你真正想要的是使用Statemonad.您可以修改您的push和pop函数以在该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)