我正在尝试使用相互依赖的velocity
和location
线来使对象从墙上弹回。简单的一维示例如下所示:
{-# LANGUAGE Arrows #-}
import Prelude hiding ((.), id)
import Control.Wire
import FRP.Netwire
import Control.Monad.IO.Class
-- location -> (corrected-location, did-bounce)
-- "reflect" location back behind the border and indicate the bounce
checkW :: (HasTime t s) => Wire s () IO Double (Double, Bool)
checkW = mkSF_ check
where
check loc
| loc < 0 = (-loc, True)
| loc > 1 = (2-loc, True)
| otherwise = (loc, False)
-- did-bounce -> velocity, initial velocity in the argument
velW :: Double -> Wire s () IO Bool Double
velW iv = mkSFN $ \bounce -> (iv, velW (if bounce then -iv else iv))
-- produce tuple (location, velocity)
locvelW :: (HasTime t s) => Wire s () IO a (Double, Double)
locvelW = proc _ -> do
rec (loc, bounce) <- (checkW . integral 0.5) -< vel
vel <- (velW 0.3) -< bounce
returnA -< (loc, vel)
main :: IO ()
main = testWireM liftIO clockSession_ locvelW
如果我执行此操作,在第一个反弹速度开始在每一步的负值和正值之间翻转。
我知道我可以修复&#34;它通过发信号通知速度线使速度为负或正,这取决于我弹回的边界。有用。但我想了解为什么我看到这种行为,我知道翻转应该只发生一次,因为我明确地将对象推送到边框的另一侧。我怀疑懒惰在这里发挥作用,也许战略性地放置seq
会使其发挥作用&#34;按照预期&#34;。
我希望得到一个解释,并建议如何解决它而不诉诸&#34;蛮力&#34;溶液
答案 0 :(得分:3)
此行为是由velW
中的简单逻辑错误引起的。 velW
在弹跳时不会改变速度,它只会在下次计算速度时改变初始速度;他们都应该改变。这是一个正确的版本。
-- did-bounce -> velocity, initial velocity in the argument
velW :: Double -> Wire s e m Bool Double
velW iv = mkSFN $ \bounce -> let vel = if bounce then -iv else iv in (vel, velW vel)
懒惰不能在这里发挥作用。懒惰影响计算何时发生,但它不会影响计算的含义。纯计算不受副作用的影响,因此其结果并不取决于何时进行评估。