netwire:处理相互依赖的电线中的懒惰(?)

时间:2014-11-20 22:59:42

标签: haskell lazy-evaluation netwire

我正在尝试使用相互依赖的velocitylocation线来使对象从墙上弹回。简单的一维示例如下所示:

{-# 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;溶液

1 个答案:

答案 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)

懒惰不能在这里发挥作用。懒惰影响计算何时发生,但它不会影响计算的含义。纯计算不受副作用的影响,因此其结果并不取决于何时进行评估。