Haskell中MutVar#是否为不纯操作?State/ST/STRef相关困惑
解析Haskell中MutVar#的纯性疑问
核心结论
MutVar# 及其相关API是纯的,你产生误解的根源是忽略了 State# 作为操作输入的关键作用。
关键概念澄清
State# RealWorld不是普通的"值",它是程序全局状态的唯一令牌。每次涉及可变操作(如创建、读写MutVar#)时,都会生成一个新的State#,代表操作完成后的世界状态。- Haskell的纯性要求是相同输入必须得到相同输出,而MutVar#的操作(如
readMutVar#)的输入是**MutVar# s a+State# s**的组合,而非单独的MutVar#。
针对你的代码分析
你的代码中,readMutVar#的调用并非使用"相同输入":
fun :: State# RealWorld -> (Int, Int, Int) fun s# = let (# a#, var# #) :: (# State# RealWorld, MutVar# RealWorld Int #) = newMutVar# 0 s# -- 传入原始状态s#,此时var#在s#对应的状态下值为0 (# b#, o1 #) :: (# State# RealWorld, Int #) = readMutVar# var# s# -- 基于new后的状态a#执行写入,得到新状态c# c# = writeMutVar# var# 10 a# -- 传入写入后的状态c#读取,得到10 (# d#, o2 #) :: (# State# RealWorld, Int #) = readMutVar# var# c# -- 基于c#执行第二次写入,得到新状态e# e# = writeMutVar# var# 20 c# -- 传入e#读取,得到20 (# f#, o3 #) :: (# State# RealWorld, Int #) = readMutVar# var# e# in (o1, o2, o3)
- 每次
readMutVar#的State#输入都是不同的(s#、c#、e#),因此输入组合(var#+State#)并不相同,输出不同完全符合纯函数的要求。 - 当你多次传入
realWorld#调用fun时,每次都会得到相同的(0,10,20)结果,这证明fun是纯函数——相同输入始终得到相同输出。
ST/State与纯性的关联
StateMonad的s -> (s,a)结构是纯函数式的状态传递,通过显式传递不可变的状态值来模拟状态变化。STMonad则是通过State#和类型系统(带 phantom types)来封装可变操作,确保可变变量无法逃逸出ST作用域,从而在保证局部可变性的同时,维持整个程序的纯性。MutVar#是STRef的底层实现,它的操作必须结合State#来使用,而State#的传递确保了操作顺序和状态一致性,全程没有违反纯性。
内容的提问来源于stack exchange,提问作者kwonryul
相关产品推荐
相关产品推荐

