在Haskell的状态monad“ Stack”上调用函数

时间:2019-02-18 13:58:19

标签: haskell state monads

任务提供了以下类型

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

我要写的是函数 1.推动将整数放入堆栈 2.弹出以返回并删除最高的对象

我试图通过状态单子查询Google以了解它们,但我得到了这个概念,但是我无法使用给定的类型结构来实现它。

1 个答案:

答案 0 :(得分: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)
  }

popMaybe 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
    }

它给我们带来什么?我们终于可以使用我们的poppush函数了:

simpleStack :: Stack Int
simpleStack = do
  push 10
  push 20
  push 30
  Just x <- pop
  return x

我们可以这样测试:

main :: IO ()
main = putStrLn $ show $ fst $ run simpleStack []