Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List 使用>>;=和=<&书信电报;在Haskell中组合IO的运算符_List_Haskell_Monads_Lazy Evaluation_Lazy Sequences - Fatal编程技术网

List 使用>>;=和=<&书信电报;在Haskell中组合IO的运算符

List 使用>>;=和=<&书信电报;在Haskell中组合IO的运算符,list,haskell,monads,lazy-evaluation,lazy-sequences,List,Haskell,Monads,Lazy Evaluation,Lazy Sequences,我正在尝试运行“无限”模拟,打印每个步骤的结果 有一个函数nextframe,它接受一个输入Map,并向前推进模拟以返回一个输出Map,然后有一个render\uu函数,它接受一个输入Map,并将一些东西打印到stdout,返回输入Map(这样我就可以使用迭代或类似的方法) 由于我对Haskell比较陌生,所以我真的很难将所有这些部分放在一起。我发现非常有趣,但由于这两个函数的组合,我不确定如何直接将其付诸实践(我尝试过使用liftM2和iterate) 类型签名如下所示: nextframe:

我正在尝试运行“无限”模拟,打印每个步骤的结果

有一个函数
nextframe
,它接受一个输入
Map
,并向前推进模拟以返回一个输出
Map
,然后有一个
render\uu
函数,它接受一个输入
Map
,并将一些东西打印到
stdout
,返回输入
Map
(这样我就可以使用
迭代
或类似的方法)

由于我对Haskell比较陌生,所以我真的很难将所有这些部分放在一起。我发现非常有趣,但由于这两个函数的组合,我不确定如何直接将其付诸实践(我尝试过使用
liftM2
iterate

类型签名如下所示:

nextframe::Map->IO映射
渲染:映射->IO映射--原始映射->IO()
我真的不知道该从这里走到哪里,我可以这样做:

(迭代(>>=nextframe)初始映射)::[IO映射]

但这只是给了我一个(无限?)帧列表(我认为),这很好,它不允许我打印它们,因为我不知道如何在其中组合渲染功能。

iterate
对于非IO计算非常有效,但是如果你在
IO
中,你就不能轻易地利用
iterate

要了解原因,请列出您的列表

(iterate (>>= nextFrameR) initialMap) :: [IO Map]

那么…我们怎么能利用它来产生一个无限循环呢?我们不能接受不存在的“最后一个元素”。我们也不能按顺序执行该列表中的所有操作,因为这会运行多次
initialMap

如果我们避免使用
iterate
并求助于递归之类的基本方法,则会更容易:

loop :: Map -> IO ()
loop m = do
   m' <- nextFrameR m
   render_ m'       -- it looks like you want this
   -- feel free to add some delay here, or some stopping condition to exit the loop
   loop m'

main :: IO ()
main = do
   m <- initialMap
   loop m
loop::Map->IO()
循环m=do
m'=
但是没有必要这样做

最后,无需使
render\uuu
返回相同的
Map
。您可以使该返回
IO()


如果你是初学者,我建议你一开始不要使用“智能”像
mapM\u、遍历、for、sequence、liftM2、ap、
这样的库函数,并学会只使用
do
-块和递归来做任何事情。然后,一旦你了解了它的工作原理,你就可以试着利用库帮助来改进你的代码。

表达式
sequence(iterate(>=nextframe)initialMap)
将具有
IO[Map]
类型。但是,与在早期阶段涉及IO不同,您可以使用:
frames=iterate nextFrameR initialMap
,编写一个类型为
Map->String
的普通渲染函数。然后使用
Map render frames
查看文本跟踪输出。至于是否使用IO的决定应该留给最高层el调用代码。问题是
nextFrameR
在每次运行时都会创建一个
newStdGen
。我有一个版本的代码,它接受
RandomGen
(这就是
nextFrameR
在引擎盖下调用的内容)但我不在顶层。我明白了,但在每一步创建一个新的生成器有点不寻常。你可以在步骤N中传递随机数生成器的最终状态,使之成为步骤N+1中生成器的初始状态。这样你就可以得到统计保证,这只在单个随机序列中可用。如果你想的话为了能够使用相同的随机数但不同的物理参数运行稍后的模拟,newStdGen使这不可能,因为您无法控制种子。@jpmarinier这就是为什么我有一个版本的函数采用
RandomGen
()。我认为这解决了您正在谈论的问题,但可能没有?我确实希望能够获得可复制的测试结果。不完全是这样。我在您的Github页面中看到,您的函数具有以下类型签名:
nextFrame::RandomGen=>gen->Map->Map
。因此,它不会保留生成器的最终状态以备将来使用访问。您可能需要此签名:
nextFrame::RandomGen=>gen->Map->(Map,gen)
。但是我看到库
shuffle'
函数会放弃最终状态。在其源代码中看到对
fst
的调用,并且没有对
snd
的调用。因此,您必须调整
shuffle'
源代码,或者安排使用
shuffleM
runRand
一起使用。我解决这一问题的本能会很好我一直在用一个
do
块来解决这个问题,但是在用这个块编写了一些代码,然后重构为使用>>=等之后,我也在尝试同样的方法。你是对的,我可能应该先尝试一个更简单的版本,我现在就试试看它是否有效。这很有效,但是根据最初的问题,有没有一个好的方法来使用v各种各样的操作员将代码转换成“更智能”的东西或者不是真的?感觉就像这些单子和各种操作符就是为这种事情而设计的。@GTF这是一个品味的问题。简单的
do
代码很短,任何人都可以阅读。我无法立即看到如何仅使用常用的助手来实现这一点。当然,有太多的非常用的助手,例如,哪个可以这似乎正是您所需要的。这应该仍然可以,但在使用高级帮助程序时,请始终检查代码是否仍然可读。当代码不可读时,编写“聪明”代码是没有意义的。“基本”不包括适当的流式API可能会让新手感到困惑。人们学习了那些在纯上下文中完美工作的漂亮列表处理函数,但一旦在某个地方添加了效果,就会发现
mapM
和朋友们并没有按需要“流式处理”。然后,人们就只能编写更多的“整体式”一元块在一定程度上耦合了生成和处理,给人的印象是这些高级函数是为纯世界保留的。@GTF如果您真的想使用现有的运算符,您可以编写
loop :: Map -> IO ()
loop m = do
   m' <- nextFrameR m
   render_ m'       -- it looks like you want this
   -- feel free to add some delay here, or some stopping condition to exit the loop
   loop m'

main :: IO ()
main = do
   m <- initialMap
   loop m