【发布时间】:2021-04-04 13:01:01
【问题描述】:
我正在尝试运行“无限”模拟,打印每个步骤的结果。
有一个函数 nextFrameR 接受输入 Map 并向前模拟以返回输出 Map,然后有一个 render_ 函数接受输入 Map 并将一些内容打印到 @ 987654328@,返回输入Map(这样我就可以使用iterate 或类似的东西)。
我真的很难将所有这些部分放在一起,因为我对 Haskell 来说还比较陌生。我发现this answer 非常有趣,但由于这两个功能的结合,我不确定如何直接将其付诸实践(我尝试过使用liftM2 和iterate)。
类型签名如下:
nextFrameR :: Map -> IO Map
render_ :: Map -> IO Map -- originally Map -> IO ()
我不确定从这里去哪里,我可以这样做:
(iterate (>>= nextFrameR) initialMap) :: [IO Map]
但这只是给了我一个(无限?)帧列表(我认为),这很好,它只是不让我打印它们,因为我不知道如何在那里组合渲染功能。
【问题讨论】:
-
表达式
sequence (iterate (>>= nextFrameR) initialMap)将具有IO [Map]类型。但是,与其在早期阶段涉及 IO,您可以使用:frames = iterate nextFrameR initialMap,编写一个Map -> String类型的普通渲染函数。然后使用map render frames查看文本跟踪输出。恕我直言,是否使用 IO 的决定应该留给顶层调用代码。 -
问题是
nextFrameR在每次运行时都会创建一个newStdGen。我有一个代码版本,它采用RandomGen(这是nextFrameR在后台调用的),但我不在顶层。 -
我明白了,但是在每一步都创建一个新的生成器有点不寻常。您可以将步骤 N 中随机数生成器的最终状态传递为步骤 N+1 中生成器的初始状态。这样,您将获得统计保证,这些保证仅在单个随机系列中可用。如果您希望能够使用相同的随机数但不同的物理参数运行以后的模拟,那么 newStdGen 使这成为不可能,因为您无法控制种子。
-
@jpmarinier 这就是为什么我有一个使用
RandomGen代替的函数版本(github.com/gfarrell/tron-lines/blob/…)。我认为这解决了您正在谈论的问题,但也许没有?我确实希望能够获得可重复的测试结果。 -
不完全是。我在您的 Github 页面中看到您的函数具有这种类型签名:
nextFrame :: RandomGen gen => gen -> Map -> Map。因此它不会保留生成器的最终状态以供进一步处理。你可能想要这个签名:nextFrame :: RandomGen gen => gen -> Map -> (Map, gen)。但我看到 libraryshuffle'函数 drops 最终状态。请参阅其源代码中对fst的调用,而不是对snd的调用。因此,您将不得不调整shuffle'源代码或安排将shuffleM与runRand一起使用。
标签: list haskell monads lazy-evaluation lazy-sequences