2

相互に依存するワイヤvelocityを使用して、オブジェクトを壁から跳ね返らせようとしています。location単純な 1 次元の例は次のようになります。

{-# 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

この動作は、 の単純な論理エラーが原因ですvelWvelWバウンドするときに速度を変更するのではなく、次に速度が計算されるときの初期速度を変更するだけです。どちらも変更する必要があります。これが正しいバージョンです。

-- 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 に答える