Pop и push довольно просты:
push :: Int -> Stack ()
push x = T { run = \st -> ((), x : st) }
pop :: Stack (Maybe Int)
pop = T
{ run = \st -> case st of
(x : xs) -> (Just x, xs)
_ -> (Nothing, st)
}
pop
- это тип Maybe Int
, поскольку стек может быть пустым.В этом случае мы просто возвращаем Nothing
.Но что мы можем с этим сделать?Ну, не много без Monad
экземпляра.Давай сделаем один.Сначала нам нужно Functor
и Applicative
экземпляров:
instance Functor (Trans st) where
fmap f (T r) = T
{ run = \st ->
let (result, state) = r st
in (f result, state)
}
instance Applicative (Trans st) where
pure a = T { run = \st -> (a, st) }
(<*>) (T fr) (T r) = T
{ run = \st ->
let (result, state) = r st
(f, nextState) = fr state
in (f result, nextState)
}
instance Monad (Trans a) where
(>>=) (T r) f = T
{ run = \st ->
let (result, state) = r st
in run (f result) state
}
Что это нам дает?Наконец, мы можем использовать наши pop
и push
функции:
simpleStack :: Stack Int
simpleStack = do
push 10
push 20
push 30
Just x <- pop
return x
И мы можем проверить это следующим образом:
main :: IO ()
main = putStrLn $ show $ fst $ run simpleStack []