重复状态,直到它没有变化/稳定

时间:2017-06-05 20:40:31

标签: haskell monads

我正在尝试重复运行状态转换,直到状态不变。我searched Hoogle代表

Eq s => State s () -> State s ()

但没有发现任何看起来合适的东西。

如何反复运行状态转换,直到它没有改变?

5 个答案:

答案 0 :(得分:5)

您可以在State中执行此操作,但没有特别的好处。为什么不:

idempotently :: Eq a => (a -> a) -> a -> a
idempotently f a = if a' == a then a else idempotently f a' where a' = f a

idempotentlyM :: Eq s => (s -> s) -> State s ()
idempotentlyM f = modify (idempotently f)

如果您从State s ()开始,则execState可以s -> s将其发送出去。

当然,我们无法保证f不会分歧,因此idempotently f可能永远不会终止。

答案 1 :(得分:4)

您正在计算状态转换的定点。 但是我们不能使用import MapKit class RedRocksPin: NSObject, MKAnnotation { var title: String? var subtitle: String? var coordinate: CLLocationCoordinate2D init(title:String, subtitle:String, coordinate: CLLocationCoordinate2D) { self.title = title self.subtitle = subtitle self.coordinate = coordinate } ,因为我们处于monadic环境中。 所以让我们使用monadic fix-point combinator代替。 输入fix

mfix

我还冒昧地将你的函数推广到了你可以提供用户提供的二元谓词。

使用ghci import Control.Monad (unless) import Control.Monad.State (MonadState, StateT, get, put) import Control.Monad.Fix (mfix) import Control.Monad.IO.Class (liftIO) untilStable :: MonadState s m => (s -> s -> Bool) -> m a -> m () untilStable p = mfix $ \f st -> p <$> get <* st <*> get >>= (`unless` f) 永远不会终止。 但是:

runState (untilStable (==) $ modify (+1)) 2

你得到:

comp :: StateT Int IO ()
comp = do
  s1 <- (+1) <$> get
  liftIO $ print s1
  let s2 = if s1 >= 3 then 3 else s1
  put s2

> runStateT (untilStable (==) comp) 0 1 2 3 4 ((),3) 可以进一步概括为:

untilStable

现在我们已经释放了计算可能导致的类型。

修复您想要untilStable :: MonadState s m => (s -> s -> Bool) -> m a -> m a untilStable p = mfix $ \f st -> do before <- get a <- st after <- get if p before after then pure a else f 实施idempotently,您可以这样做:

fix

答案 2 :(得分:2)

您可以使用getunless

滚动自己的更高级别的递归转换
untilStable :: Eq s => State s () -> State s ()
untilStable stateTransform = do
  before <- get
  stateTransform
  after <- get
  unless (before == after) $ untilStable stateTransform

答案 3 :(得分:1)

https://stackoverflow.com/a/44378096/1319998https://stackoverflow.com/a/23924238/1319998中获取灵感,您可以使用State执行此操作但使用某些函数monad magic ...

untilStable :: Eq a => (a -> a) -> a -> a
untilStable = until =<< ((==) =<<)

...使用s -> s

从状态中提取execState
untilStable (execState stateTransformToRunRepeatedly) initialState

答案 4 :(得分:1)

扩展https://stackoverflow.com/a/44381834/1319998的答案,因此保持迭代超出State,但避免使用monad magic函数,更明确地使用until

untilStable :: Eq a => (a -> a) -> a -> a
untilStable f a = until (\w -> f w == w) f a

...并且类似地提取s - &gt; s来自使用execState的状态

untilStable (execState stateTransformToRunRepeatedly) initialState

没有使用无点样式,但对我来说更清楚的是发生了什么。

另外,我想知道这是否会导致这个和https://stackoverflow.com/a/44381834/1319998效率低下,其中f a可以计算两次:一次私有until,一次在用于测试的谓词中是否要停止。