我之前已经解决过这个问题 - 解决它的方法之一是使用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
因为first
function 有一个函数可以将 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)
stateUnfoldr
State s [d]
runState
如果您只需要状态或列表,我们也可以使用execState
orevalState
代替。runState