[英]Using Maybe with State Monad
I'm trying to implement a FIFO Queue in Haskell with push/pop/peek operations, and this is what I got so far. 我正在尝试使用push / pop / peek操作在Haskell中实现FIFO队列,这是我到目前为止所做的。
data Queue a = Queue {
inbox :: [a],
outbox :: [a]
} deriving (Eq, Show)
push :: a -> Queue a -> Queue a
push e (Queue inb out) = Queue (e:inb) out
pop :: Queue a -> (Maybe a, Queue a)
pop q =
case top of
Nothing -> (top, emptyQueue)
Just elem -> (Just elem, poppedQueue)
where
(top, q') = peek q
poppedQueue = Queue (inbox q') (tail $ outbox q')
peek :: Queue a -> (Maybe a, Queue a)
peek q@(Queue [] []) = (Nothing, emptyQueue)
peek q@(Queue inb []) = peek $ Queue [] (reverse inb)
peek q@(Queue _ outb) = (Just $ head outb, q)
emptyQueue = Queue [] []
So the above works, and I can push/pop/peek at my Queue. 所以上面的工作,我可以推/我/我的队列。 As you see, I wrapped up the return type in a Maybe, so that I get a Nothing if I pop an empty queue or peek at an empty queue, and a Just element otherwise.
如你所见,我将一个返回类型包含在一个Maybe中,这样如果我弹出一个空队列或者查看一个空队列,我就得到一个Nothing,否则就是Just元素。
So I also thought I could use the State monad to easily chain operations. 所以我也认为我可以使用State monad轻松连接操作。 I proceeded as follows:
我进行如下:
type QueueState a = State (Queue a)
pushQueue :: a -> QueueState a ()
pushQueue e = state $ \q -> ((),push e q)
popQueue :: QueueState a (Maybe a)
popQueue = state $ \q -> pop q
Allright, so that seems to work. 好吧,所以这似乎工作。 I can do:
我可以:
runState (pushQueue 2 >> pushQueue 3 >> popQueue >> pushQueue 1 >> popQueue) emptyQueue
and get back (Just 3,Queue {inbox = [1], outbox = []})
, which is what I wanted. 然后回来
(Just 3,Queue {inbox = [1], outbox = []})
,这就是我想要的。 But I can't do something like: 但我做不了类似的事情:
runState (pushQueue 2 >> popQueue >>= pushQueue) emptyQueue
which results in an: 这导致:
Occurs check: cannot construct the infinite type: a0 = Maybe a0
Expected type: Maybe a0
-> StateT (Queue a0) Data.Functor.Identity.Identity ()
Actual type: Maybe a0 -> QueueState (Maybe a0) ()
Now I think I understand why that this, but I can't figure out how to make it do what I want. 现在我想我明白为什么会这样,但我无法弄清楚如何让它做我想做的事。 That is, a chaining using
>>=
from a pop
should be able to feed into a push
. 也就是说,使用
>>=
来自pop
的链接应该能够进入push
。 I'm thinking I might need to use a StateT transformer, but I don't really understand them yet, so I'm looking for help on how do implement that functionality. 我想我可能需要使用StateT转换器,但我还没有真正理解它们,所以我正在寻找有关如何实现该功能的帮助。 Or do I need to do this in a completely different way?
或者我是否需要以完全不同的方式执行此操作? Thanks.
谢谢。
It is because the compiler can not construct an infinite type ;-). 这是因为编译器无法构造无限类型;-)。
More helpfully, consider the line: 更有帮助的是,考虑一下:
runState (pushQueue 2 >> popQueue >>= pushQueue) emptyQueue
What is the type of popQueue
? popQueue
的类型是popQueue
? QueueState Int (Maybe Int)
. QueueState Int (Maybe Int)
。 (think m (Maybe Int)
) (想想
m (Maybe Int)
)
What is the type of >>= pushQueue
? 什么是
>>= pushQueue
的类型? QueueState Int Int -> QueueState Int ()
(think m Int -> m ()
) QueueState Int Int -> QueueState Int ()
(想想m Int -> m ()
)
So the typechecker tries to unify the types Maybe a
and a
- the only way those types unify is if a
if an infinite type of Maybe (Maybe (Maybe (Maybe ...
. 所以typechecker试图统一类型
Maybe a
和a
-这些类型的统一的唯一途径是,如果a
如果无限类型的Maybe (Maybe (Maybe (Maybe ...
。
The solution is to do something to handle the Nothing
case. 解决方案是做一些事来处理
Nothing
案例。 For example, return ()
or push depending on the Maybe. 例如,
return ()
或push取决于Maybe。
runState (pushQueue 2 >> popQueue >>= maybe (return ()) pushQueue) emptyQueue
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.