我之前已经解决过这个问题 - 解决它的方法之一是使用State monad。
简单来说,它们处理表单上的函数s -> (d, s)。直观地说,s是在计算过程中可能改变的状态类型。
首先要注意的是s -> Maybe (d, s)没有形式s -> (d, s):前者是一个元组,而后者是一个Maybe,我们需要一个函数类型s -> (Maybe d, s),如果函数返回None,修改后的函数将返回之前的状态。此适配器的一种可能实现是:
keepFailure :: (s -> Maybe (d, s)) -> (s -> (Maybe d, s))
keepFailure f s = maybe (Nothing, s) (first Just) (f s)
请记住,import Data.Bifunctor因为firstfunction 有一个函数可以将 from 转换s -> (d, s)为State s d被调用state,并将
runState其转换回来。现在我们实现一个函数,它将尝试耗尽所有可能值的状态:
stateUnfoldr :: State s (Maybe d) -> State s [d]
stateUnfoldr f = do
mx <- f
case mx of
Just x -> do
xs <- stateUnfoldr f
return $ x:xs
Nothing -> return []
简单来说,mx <- f就像“应用f到输入,更新状态,获取返回值给mx”然后,我们可以把所有东西拼凑在一起:
fStateUnfoldr :: (s -> Maybe (d, s)) -> (s -> ([d], s))
fStateUnfoldr f = runState $ stateUnfoldr $ state . keepFailure $ f
记得import Control.Monad.State
state . keepFailure适应Monad,然后展开为 a f,然后将其转回函数。State s (Maybe d)stateUnfoldrState s [d]runState
如果您只需要状态或列表,我们也可以使用execStateorevalState代替。runState