2

我正在尝试使用相互依赖的电线使物体从墙壁上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

如果我运行这个,在第一次反弹速度开始在每一步之间在负值和正值之间翻转之后

我知道我可以通过向速度线发出信号来“修复”它,根据我反弹的边界来使速度为负或正。有用。但我想了解为什么我会看到这种行为,我知道翻转应该只发生一次,因为我明确地将对象推到边框的另一侧。我怀疑懒惰在这里发挥了作用,也许战略性地放置seq会使它“按预期”工作。

我想要一个解释,并建议如何在不诉诸“蛮力”解决方案的情况下解决它。

4

1 回答 1

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)

懒惰在这里无法发挥作用。惰性会影响计算发生的时间,但不会影响计算的含义。纯计算不受副作用影响,因此其结果不依赖于何时评估。

于 2014-11-21T02:57:59.283 回答