Haskell非确定性转移系统随机轨迹生成的随机数生成器故障排查
代码问题排查及修复
存在的问题
- 缺失必要导入:代码中使用了
List.unfoldr但未导入Data.List,同时没有定义TrSys类型别名,直接运行会报编译错误。 - 集合索引越界:
Set.elemAt的合法索引范围是0到Set.size cs - 1,现有代码随机数范围写为(0, Set.size (tr c)),当随机到等于集合大小的数值时会直接抛出越界异常。 - 随机逻辑完全失效:每次调用
next函数时都用固定种子r重新初始化StdGen,导致每次取到的第一个随机数s永远是同一个值,不仅没有随机性,你定义的ss随机序列也完全没有被使用。 - 重复计算冗余:同一个状态的转移集合被重复计算了多次,没必要反复调用
tr c。
修复后的代码
首先补充必要的类型定义和导入:
import qualified Data.Set as Set import Data.List (unfoldr) import System.Random (StdGen) import qualified System.Random as Random -- 补充转移系统的类型定义:TrSys是状态到后续状态集合的映射 type TrSys a = a -> Set.Set a
修复后的函数实现:
rngTrace :: Int -> TrSys a -> a -> [a] rngTrace seed tr initial = initial : unfoldr next (initial, Random.mkStdGen seed) where next (currState, gen) = let nextStates = tr currState size = Set.size nextStates in if size == 0 then Nothing else let (s, newGen) = Random.randomR (0, size - 1) gen nextState = Set.elemAt s nextStates in Just (nextState, (nextState, newGen))
修复说明
- 把随机生成器的状态作为迭代参数传递,每次生成随机数后更新生成器状态,保证后续随机数的独立性。
- 修正了随机数的上下界范围,避免越界错误。
- 移除了重复计算的逻辑,转移集合只计算一次。
- 补充了缺失的导入和类型定义,可直接编译运行。
内容的提问来源于stack exchange,提问作者AndreeaC26
相关产品推荐
相关产品推荐

