【发布时间】:2026-01-16 01:00:01
【问题描述】:
我想要一个类似的功能:
unzipState :: (MonadState s m) => m (a, b) -> (m a, m b)
这将采用返回元组的(有状态的)计算,并将返回两个(依赖的)计算。
当然,困难在于从一个或另一个计算中提取值应该更新另一个计算中的状态。
一个有用(和激励)的应用程序是 Random monad,表示为
{-# LANGUAGE Rank2types #-}
import qualified System.Random as SR
import Control.Monad.State
type Random a = forall r. (State RandomGen r) => State r a
假设你有:
normal :: Random Double
-- implementation skipped
correlateWith :: Double -> Random (Double, Double) -> Random (Double, Double)
correlateWith rho w = do
(u, v) <- w
return $ (u, p * u + (1 - p * p) * v)
会写是很自然的:
let x = normal
y = normal
(u, v) = unzipState $ correlateWith 0.5 $ liftM2 (,) x y
... now I am able to perform computation on u and v as correlated random variables
有没有明智的方法来做到这一点?我挣扎了一下,但没有设法得到任何东西。 Hoogle 也无济于事。
编辑
很好的答案表明我的问题定义不明确。尽管如此,有人可以解释我为什么以下python中的实现(我认为是正确的,但没有进行太多测试)不能在Haskell中翻译(具有STrefs,闭包和其他东西的魔力我承认我不明白;-)):
def unzipState(p):
flist, glist = [], []
def f(state):
if not flist:
(fvalue, gvalue), newstate = p(state)
glist.insert(0, gvalue)
return (fvalue, newstate)
else:
fvalue = flist.pop()
return (fvalue, state)
def g(state):
if not glist:
(fvalue, gvalue), newstate = p(state)
flist.insert(0, fvalue)
return (fvalue, newstate)
else:
gvalue = glist.pop()
return (gvalue, state)
return (f, g)
我并不是说可以在 Haskell 中翻译有状态代码,但我觉得理解 why 和 when(即使是在示例中)它无法完成会大大提高了我的理解力。
edit2
现在很清楚了。函数 f 和 g 显然不是纯函数,因为它们的输出不仅取决于 state 的值。
再次感谢!
【问题讨论】:
-
既然你提到了随机值生成器的例子:*.com/a/32000364;它的界面类似于您正在寻找的界面。
标签: haskell random state monads