[英]Haskell Couldn't match type `Stack' with `IO'
this is my first time to use Haskell and i have read many many tutorials about it. 这是我第一次使用Haskell,我已经阅读了很多关于它的教程。 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. 我试图建立一个堆栈数据结构并在Do块中使用它。 But when i do this. 但是当我这样做的时候。 It says cant match type'Stack' with 'IO', i have no idea about this problem. 它说不能匹配类型'堆'与'IO',我不知道这个问题。 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) 问题在下面(当我把推出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
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
. 这里的问题是main
具有类型IO ()
,这意味着do
块中的任何语句必须具有某种类型a
类型IO a
a
。 Your data type is Stack a
, which does not match IO a
. 您的数据类型是Stack a
,它与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. Haskell中的值是不可变的 ,这意味着它们在声明后不能被修改。 For most purposes, Haskell doesn't have variables, just named values. 在大多数情况下,Haskell没有变量,只有命名值。
What you probably really want is to use the State
monad. 你可能真正想要的是使用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: 您可以修改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'
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. 你甚至在元组的第一个元素中pop
返回Maybe a
直接进入state
函数。 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]
push 0 mystack
returns a new stack. push 0 mystack
返回一个新堆栈。 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. “动作”是改变系统全局状态的东西,它们由返回IO的函数标记。 Since push
doesn't change the global state, haskell tells you that there's no reason to call it like you do. 由于push
不会改变全局状态,因此haskell告诉你没有理由像你那样调用它。
What you probably mean is: 你的意思是:
let newStack = push 0 mystack
Inside a do
block, consecutive lines like: 在do
块内,连续的行如:
do
print list
print "something else"
get translated to: 被翻译成:
print list >> print "something else"
where >>
has type IO a -> IO b -> IO b
when using IO
as you are here. 其中>>
具有类型IO a -> IO b -> IO b
,因为您在这里使用IO
。
So for: 因此对于:
print list
push 0 mystack
to compile, push 0 mystack
must return an IO a
for some type a
, however push 0 mystack
returns a Stack Integer
, hence the error. 要编译, push 0 mystack
必须为某个类型a
返回一个IO a
,但是push 0 mystack
返回一个Stack Integer
,因此出错。
If you want to bind a regular value inside a do
block you can use let
eg 如果要在do
块中绑定常规值,可以使用let
eg
let stack' = push 0 mystack
Other answers have already proposed a few solutions. 其他答案已经提出了一些解决方案。 Here, let me comment about what your code actually means. 在这里,让我评论一下你的代码实际意味着什么。 Let us focus on your main
: 让我们专注于您的main
:
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()
As the error points out, the problem lies in the push 0 mystack
line. 正如错误所指出的那样,问题在于push 0 mystack
行。 Now, Haskell is a pure language in which every defined value (such as push
, or mystack
) can be replaced by its own definition without affecting the program meaning. 现在,Haskell是一种纯语言,其中每个定义的值(例如push
或mystack
)都可以被其自己的定义替换而不会影响程序的含义。 This feature is often called "referential transparency". 此功能通常称为“参照透明度”。 We can then state that the line 然后我们可以说明这一行
push 0 mystack
is equivalent to (by definition of mystack
) 相当于(根据mystack
的定义)
push 0 empty
which is equivalent to (by definition of empty
) 相当于(按empty
的定义)
push 0 (Stack [])
which is equivalent to (by definition of push
) 相当于(按push
的定义)
Stack (0:[])
which can be written using the more common syntax as 可以使用更常见的语法编写
Stack [0]
Hence, your main
actually means 因此,你的main
实际意味着
main = do
arr <- newArray((0,0),(8,13)) 0 ::IO (IOArray(Int,Int) Int)
list <- getElems arr
print list
Stack [0] --here is the problem
return()
Now it is easy to see that the problematic line is indeed such. 现在很容易看出问题线确实如此。 It mentions a Stack
value, but it does not specify what to do on that. 它提到了一个Stack
值,但它没有指定该怎么做。 We could, for instance, just print it using 例如,我们可以使用它来打印它
print (Stack [0]) -- or, equivalently, print (push 0 mystack)
or we could define a variable with such value 或者我们可以定义具有此值的变量
let s = Stack [0] -- or, equivalently, let s = push 0 mystack
...
print s
In general we could do anything with such a value. 一般来说,我们可以用这样的价值做任何事情。
In the case you were trying to "modify" the value of mystack
, know that you can not in a pure language as Haskell. 在你试图“修改” mystack
的值的mystack
,要知道你不能用纯语言作为Haskell。 Indeed, to modify the value of mystack
is as meaningful as modifying the value of Stack []
, by referential transparency. 实际上,修改mystack
的值与通过引用透明度修改Stack []
的值一样有意义。 Haskell variables denote values rather than mutable memory cells. Haskell变量表示值而不是可变存储单元。 Perhaps surprisingly at first, one can often program without mutable variables. 也许首先令人惊讶的是,人们通常可以编程而没有可变变量。 This might feel impossible, or impractical, when one has been programming in an imperative language since a long time, but once accustomed with pure functional programming this feels very natural, and pays back in many ways (eg allowing equational reasoning about code, much fewer concerns on concurrent programming, etc.). 这可能感觉不可能或不切实际,因为很久以来一直用命令式语言进行编程,但是一旦习惯了纯函数编程,这种感觉非常自然,并且在很多方面得到回报(例如,允许对代码进行等式推理,更少的对并发编程的关注等)。 When you really need mutable state, you can use the State
monad, or the IO
moand and IORef
s, or ST
and STRef
, for instance. 当你真的需要可变状态时,你可以使用State
monad,或IO
moand和IORef
,或者ST
和STRef
。 These however should be used when the stateful approach is really the best, simplest approach to express your algorithm. 但是,当有状态方法确实是表达算法的最佳,最简单的方法时,应该使用这些方法。 In practice, this is rarely so, and even when it is, often one can still write most of the subroutines without having side effects on the state. 实际上,这种情况很少发生,即使是这样,通常人们仍然可以编写大部分子程序而不会对状态产生副作用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.