我正在尝试重复运行状态转换,直到状态不变。我searched Hoogle代表
Eq s => State s () -> State s ()
但没有发现任何看起来合适的东西。
如何反复运行状态转换,直到它没有改变?
答案 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)
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/1319998和https://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
,一次在用于测试的谓词中是否要停止。