Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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
Haskell 用反应式计算器做一些基本的微积分_Haskell_Reactive Banana - Fatal编程技术网

Haskell 用反应式计算器做一些基本的微积分

Haskell 用反应式计算器做一些基本的微积分,haskell,reactive-banana,Haskell,Reactive Banana,设置: 我正在使用反应香蕉和OpenGL,我有一个齿轮,我想旋转。我有以下信号: bTime :: Behavior t Int -- the time in ms from start of rendering bAngularVelosity :: Behavior t Double -- the angular velocity -- which can be increase or

设置

我正在使用反应香蕉和OpenGL,我有一个齿轮,我想旋转。我有以下信号:

bTime :: Behavior t Int -- the time in ms from start of rendering
bAngularVelosity :: Behavior t Double -- the angular velocity
                                      -- which can be increase or
                                      -- decreased by the user
eDisplay :: Event t ()     -- need to redraw the screen
eKey :: Event t KeyState   -- user input
最后,我需要计算
手镯
,然后通过绘图功能:

reactimate $ (draw gears) <$> (bAngle <@ eDisp)

reactimate$(牵引齿轮)(bAngle编辑:回答这个问题,是的,你使用的近似值是正确的,这是Euler解一阶微分方程的方法,对于你的目的来说足够精确,特别是因为用户没有周围角速度的绝对值来判断你Interval会使它更准确,但这并不重要

你可以用更少、更大的步骤来完成(见下文),但这种方式对我来说似乎是最清晰的,我希望对你来说是这样

为什么要费心使用这个较长的解决方案呢?即使
eDisplay
以不规则的间隔出现,它也可以工作,因为它计算
eDeltaT

让我们给自己一个时间事件:

eTime :: Event t Int
eTime = bTime <@ eDisplay
因此,我们可以将它们转换为三角洲:

delta :: TimeInterval -> Int
delta (t0,t1) = t1 - t0
当我们得到一个新的时间间隔
t2
时,我们应该如何更新时间间隔

tick :: Int -> TimeInterval -> TimeInterval
tick t2 (t0,t1) = (t1,t2)
让我们将其部分应用于时间,为我们提供一个间隔更新程序:

eTicker :: Event t (TimeInterval->TimeInterval)
eTicker = tick <$> eTime
由于时间是从渲染开始测量的,因此初始
(0,0)
是合适的

最后,我们只需在时间间隔上应用(
fmap
ping)
delta
,就可以得到DeltaT事件

eDeltaT :: Event t Int
eDeltaT = delta <$> eTimeInterval
然后我们可以使用它来制作
eDeltaAngle
:(编辑:更改为
(+)
,并转换为
双精度

如果你喜欢一行,你可以写

eDeltaT = delta <$> (accumE (0,0) $ tick <$> (bTime <@ eDisplay)) where
    delta (t0,t1) = t1 - t0
    tick t2 (t0,t1) = (t1,t2)

eAngle = accumE 0.0 $ (+) <$> ((*) <$> bAngularVelocity <@> eDeltaT) = 
而不是你原来的

reactimate $ (draw gears) <$> (bAngle <@ eDisp)

reactimate$(draw gears)(手镯一种简单的方法是假设
eDisplay
以固定的时间间隔发生, 并考虑<代码> BangalValue是相对的而不是绝对的度量,WHCH会给你一个非常短的解决方案。[请注意,如果
eDisplay
超出您的控制范围,或者如果它明显不规则地发射,或者规则性地变化,这是不好的,因为随着
eDisplay
间隔的变化,它会导致您的档位以不同的速度旋转。如果是这种情况,您需要我的其他(更长)方法。]

eDeltaAngle :: Event t (Double -> Double)
eDeltaAngle = (+) <$> bAngularVelocity <@ eDisplay
最后

reactimate $ (draw gears) <$> eAngle
reactimate$(牵引齿轮)e角度

是的,将积分近似为一个和是合适的,在这里,我通过对步长做出可能有点不准确的假设来进一步近似,但这是清楚的,并且应该是平滑的,只要你的
eDiscovery或多或少是规则的。

如果你愿意,你可以通过让用户改变对于你的B时间,用与>示例相同的方式。@AndrewC,我想这是你想要的链接吗?是的。.缺点:低速时抖动,高速时图形引擎过载,丑陋。我收回我的建议:使用角速度要优雅得多。我应该弄清楚
B时间
是挂钟时间。AndrewC你呢r第一个解决方案是最初的OpenGL作者所做的,它确实不平滑,尤其是在处理键盘/鼠标输入时。另外,请参阅我对您的回答,以获得制作
eDeltaT
的更好的
mapAccum
解决方案。
eAngle :: Event t Double
eAngle = accumE 0.0 eDeltaAngle
eDeltaT = delta <$> (accumE (0,0) $ tick <$> (bTime <@ eDisplay)) where
    delta (t0,t1) = t1 - t0
    tick t2 (t0,t1) = (t1,t2)

eAngle = accumE 0.0 $ (+) <$> ((*) <$> bAngularVelocity <@> eDeltaT) = 
reactimate $ (draw gears) <$> eAngle
reactimate $ (draw gears) <$> (bAngle <@ eDisp)
eDeltaAngle :: Event t (Double -> Double)
eDeltaAngle = (+) <$> bAngularVelocity <@ eDisplay
eAngle :: Event t Double
eAngle = accumE 0.0 eDeltaAngle
reactimate $ (draw gears) <$> eAngle