Hal*_*own 23 simulation haskell
我有一个关于设计我正在Haskell中工作的程序的最佳方法的问题.我正在写一个物理模拟器,这是我在标准命令式语言中做过的事情,通常主要的方法看起来像:
while True:
simulationState = stepForward(simulationState)
render(simulationState)
Run Code Online (Sandbox Code Playgroud)
我想知道如何在Haskell中做类似的事情.我有一个函数step :: SimState -> SimState和一个display :: SimState -> IO ()使用HOpenGL来绘制模拟状态的函数,但我不知道如何在各种"循环"中执行此操作,因为我可以提出的所有解决方案都涉及某种类型可变性 当谈到Haskell时,我有点像菜鸟,所以我完全有可能错过了一个非常明显的设计决定.此外,如果有一个更好的方法来构建我的整个程序,我会很高兴听到它.
提前致谢!
C. *_*ann 21
好吧,如果绘制连续状态是所有你想做的事,这是非常简单的.首先,获取您的step函数和初始状态并使用该iterate函数.iterate step initialState然后是每个模拟状态的(无限)列表.然后你可以映射display它以获得IO动作来绘制每个状态,所以你可以一起得到这样的东西:
allStates :: [SimState]
allStates = iterate step initialState
displayedStates :: [IO ()]
displayedStates = fmap display allStates
Run Code Online (Sandbox Code Playgroud)
运行它的最简单方法是使用该intersperse函数在每个显示操作之间设置"延迟"操作,然后使用该sequence_函数运行整个操作:
main :: IO ()
main = sequence_ $ intersperse (delay 20) displayedStates
Run Code Online (Sandbox Code Playgroud)
当然,这意味着您必须强制终止应用程序并排除任何类型的交互性,因此这通常不是一个好方法.
一种更明智的方法是在每一步中交错诸如"查看应用程序是否应该退出"之类的内容.你可以用显式递归来做到这一点:
runLoop :: SimState -> IO ()
runLoop st = do display st
isDone <- checkInput
if isDone then return ()
else delay 20 >> runLoop (step st)
Run Code Online (Sandbox Code Playgroud)
我首选的方法是编写非递归步骤,然后使用更抽象的循环组合器.不幸的是,在标准库中以这种方式做到并不是很好的支持,但它看起来像这样:
runStep :: SimState -> IO SimState
runStep st = do display st
delay 20
return (step st)
runLoop :: SimState -> IO ()
runLoop initialState = iterUntilM_ checkInput runStep initialState
Run Code Online (Sandbox Code Playgroud)
实现这个iterUntilM_功能留给读者练习,呵呵.
Ant*_*sky 21
在我看来,思考这个问题的正确方法不是作为循环,而是作为列表或其他这样的无限流结构.我给了一个类似的答案,以类似的问题 ; 正如CA McCann写的那样,基本思想是使用iterate stepForward initialState,其中iterate :: (a -> a) -> a -> [a]"返回[ stepForward]到[ initialState] 的重复应用的无限列表.
这种方法的问题在于您在处理monadic步骤时遇到问题,尤其是monadic渲染函数.一种方法就是提前获取列表中所需的块(可能具有类似的功能takeWhile,可能还有手动递归),然后再mapM_ render进行操作.更好的方法是使用不同的,本质上是monadic的流式结构.我能想到的四个是:
enumerator),你的渲染将是一个接收器(iteratee); 然后你可以使用管道(an enumeratee)来应用函数和/或在中间进行过滤.Producer,Consumer,和Pipe).ListTmonad变换器.这个monad变换器旨在允许您创建具有更多有用结构的monadic值列表[m a]; 例如,使用无限monadic列表变得更易于管理.该包还将列表上的许多函数概括为新类型.它提供iterateM两次功能; 在第一次令人难以置信的通用性,并且第二次专门到ListT.然后,您可以使用诸如takeWhileM进行过滤之类的功能.在一些数据结构中重复程序迭代而不是简单地使用递归的最大好处是,您的程序可以使用控制流做有用的事情.当然,没有什么太夸张的了,但是,例如,它将"如何终止"决定与"如何生成"过程分开.现在,用户(即使只是你)可以单独决定何时停止:在n步之后?在状态满足某个谓词后?没有理由用这些决定来掩盖你的生成代码,因为它在逻辑上是一个单独的问题.
Ing*_*ngo 12
你的方法没问题,你只需要记住循环在Haskell中表示为递归:
simulation state = do
let newState = stepForward state
render newState
simulation newState
Run Code Online (Sandbox Code Playgroud)
(但你肯定需要一个如何结束循环的标准.)
| 归档时间: |
|
| 查看次数: |
4482 次 |
| 最近记录: |