在Haskell中调用状态monad"Stack"上的函数

Jan*_*n v 1 monads state haskell

我们有以下类型的任务给出

newtype Trans state a = T {run :: state -> (a,state)}
type Stack a = Trans [Int] a
Run Code Online (Sandbox Code Playgroud)

我想要的是编写一个函数1.按下将一个Integer放在堆栈上2.弹出以返回并删除最高的对象

我试图谷歌通过状态monads来理解它们,我得到了概念,但我无法用给定的类型结构实现它.

Kar*_*ski 5

流行和推送相当简单:

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

pop是类型,Maybe Int因为堆栈可以为空.在那种情况下,我们回来Nothing.但我们能做些什么呢?嗯,没有一个Monad实例并不多.我们来做一个.我们首先需要FunctorApplicative实例:

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

它给了我们什么?我们终于可以用我们poppush功能:

simpleStack :: Stack Int
simpleStack = do
  push 10
  push 20
  push 30
  Just x <- pop
  return x
Run Code Online (Sandbox Code Playgroud)

我们可以这样测试:

main :: IO ()
main = putStrLn $ show $ fst $ run simpleStack []
Run Code Online (Sandbox Code Playgroud)