yampa-test-0.14.2: examples/Testing.hs
{-# LANGUAGE Arrows #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- |
-- Module : FRP.Yampa
-- Copyright : (c) Ivan Perez, 2017-2023
-- License : BSD-style (see the LICENSE file in the distribution)
--
-- Maintainer : ivan.perez@keera.co.uk
-- Stability : provisional
-- Portability : non-portable (GHC extensions)
module Testing where
-- Examples accompanying the ICFP 2017 paper.
--
-- Changes with respect to the paper:
--
-- - The signature of ballTrulyFalling' in the paper was SF () Double. It's
-- been changed to the intended meaning: TPred ()
-- - The function uniDistStreamMaxDT had the wrong type and the name on the
-- paper was: uniDistStream. This has been fixed.
--
import FRP.Yampa
import FRP.Yampa.Stream
import FRP.Yampa.QuickCheck
import FRP.Yampa.LTLFuture
import Test.QuickCheck
-- * Sample temporal predicates
-- fallingBall :: Double -> SF () Double
-- fallingBall p0 = proc () -> do
-- v <- integral0 -< -9.8
-- p <- integral0 -< v
-- returnA -< (p0 + p)
ballFellLower :: Double -> TPred ()
ballFellLower p0 = SP (fallingBall p0 >>> arr (\p1 -> p1 <= p0))
-- > evalT (ballFellLower 100) stream01
-- True
ballFallingLower :: Double -> TPred ()
ballFallingLower p0 = Always (ballFellLower p0)
-- > evalT (ballFallingLower 100) stream01
-- True
-- fallingBallPair :: Double -> SF () (Double, Double)
-- fallingBallPair p0 = fallingBall p0 >>> (identity &&& iPre p0)
ballTrulyFalling :: Double -> TPred ()
ballTrulyFalling p0 =
Always (SP (fallingBallPair p0 >>> arr (\(pn, po) -> pn < po)))
-- > evalT (ballTrulyFalling 100) stream01
-- False
ballTrulyFalling' :: Double -> TPred ()
ballTrulyFalling' p0 =
Next (Always (SP (fallingBallPair p0 >>> arr (\(pn, po) -> pn < po))))
-- > evalT (ballTrulyFalling ′ 100) stream01
-- True
bouncingBall :: Double -> Double -> SF () (Double, Double)
bouncingBall p0 v0 = switch (fallingBall'' p0 v0 >>> (identity &&& hit))
(\(p0', v0') -> bouncingBall p0' (-v0'))
--
-- fallingBall'' :: Double -> Double -> SF () (Double, Double)
-- fallingBall'' p0 v0 = proc () -> do
-- v <- arr (v0+) <<< integral -< -9.8
-- p <- arr (p0+) <<< integral -< v
-- returnA -< (p, v)
--
-- hit :: SF (Double, Double) (Event (Double, Double))
-- hit = arr
-- (\(p0, v0) -> if ((p0 <= 0) && (v0 < 0)) then Event (p0, v0) else NoEvent)
ballLower :: Double -> TPred ()
ballLower p0 = Always (SP (bouncingBall p0 0 >>> arr (\(p1, v1) -> p1 <= p0)))
-- > evalT (ballBouncingLower 100) stream05
-- False
ballBouncingLower = ballLower
ballOverFloor :: Double -> TPred ()
ballOverFloor p0 =
Always (SP (bouncingBall p0 0 >>> arr (\(p1, v1) -> p1 >= 0)))
-- > evalT (ballOverFloor 100) stream05
-- False
fallingBall :: Double -> SF () Double
fallingBall p0 = constant (-9.8) >>> integral0 >>> integral0 >>> arr (+p0)
-- ballFellLower :: Double -> TPred ()
-- ballFellLower p0 = SP (fallingBall p0, (\_ p1 -> p1 <= p0))
testFellBall = evalT (ballFellLower 100) stream0_1
testFellBall2 = evalT (ballFellLower 100) stream0_2
testFallingBall = evalT (ballFallingLower 100) stream0_1
fallingBallPair :: Double -> SF () (Double, Double)
fallingBallPair p0 = fallingBall p0 >>> (identity &&& iPre p0)
-- ballTrulyFalling :: Double -> TPred ()
-- ballTrulyFalling p0 =
-- Always $ SP (fallingBallPair p0, \() (pn,po) -> pn < po)
testBallTrulyFalling = evalT (ballTrulyFalling 100) stream0_1
-- ballTrulyFalling' :: Double -> TPred ()
-- ballTrulyFalling' p0 =
-- Next $ Always $ SP (fallingBallPair p0, \() (pn,po) -> pn < po)
testBallTrulyFalling' = evalT (ballTrulyFalling' 100) stream0_1
fallingBall'' :: Double -> Double -> SF () (Double, Double)
fallingBall'' p0 v0 = proc () -> do
v <- arr (v0 +) <<< integral -< -9.8
p <- arr (p0 +) <<< integral -< v
returnA -< (p, v)
hit :: SF (Double, Double) (Event (Double, Double))
hit =
arr (\(p0, v0) -> if (p0 <= 0 && v0 < 0) then Event (p0, v0) else NoEvent)
-- bouncingBall :: Double -> Double -> SF () (Double, Double)
-- bouncingBall p0 v0 = switch (fallingBall'' p0 v0 >>> (identity &&& hit))
-- (\(p0', v0') -> bouncingBall p0' (-v0'))
-- ballBouncingLower :: Double -> TPred ()
-- ballBouncingLower p0 =
-- Always $ SP (bouncingBall p0 0, (\_ (p1,_) -> p1 <= p0))
testBallBouncing = evalT (ballBouncingLower 100) stream0_5
showBallBouncing =
embed
(bouncingBall 100 0 >>> arr fst )
((), map (second Just) (replicate 39 (0.5, ())))
-- ballOverFloor :: Double -> TPred ()
-- ballOverFloor p0 = Always $ SP (bouncingBall p0 0, (\_ (p1, v1) -> p1 >= 0))
testBallOverFloor = evalT (ballOverFloor 100) stream0_5'
showBallBouncing1 =
embed
(bouncingBall 110.24999999999999 0 >>> arr fst )
((), map (second Just) (replicate 102 (0.5, ())))
testBallOverFloor' = evalT (ballOverFloor 110.24999999999999) stream0_5'
propTestBallOverFloor =
forAll myStream (evalT (ballOverFloor 110.24999999999999))
where myStream :: Gen (SignalSampleStream ())
myStream = uniDistStream
propTestBallOverFloorFixed =
forAll myStream (evalT (ballOverFloor 110.24999999999999))
where myStream :: Gen (SignalSampleStream ())
myStream = fixedDelayStream (1/60)
bouncingBall' p0 v0 = bouncingBall p0 v0 >>> arr fst
ballAboveFloor :: Double -> Double -> SF () (Double, Bool)
ballAboveFloor p0 v0 = proc () -> do
ballPos <- bouncingBall' p0 v0 -< ()
let aboveFloor = ballPos >= 0
returnA -< (ballPos, aboveFloor)
-- * Sample streams
stream0_1 = ((), replicate 21 (0.1, ()))
stream0_2 = ((), (replicate 20 (0.1, ())) ++ [(-1000000, ())])
stream0_5 = ((), replicate 39 (0.5, ()))
stream0_5' = ((), replicate 20 (0.5, ()))
-- ** Extended SFs
integral0 = imIntegral 0
-- * Talk
greaterThan :: SF (Int, Int) Bool
greaterThan = arr $ \(x,y) -> x > y
alwaysGreater :: TPred (Int, Int)
alwaysGreater = Always $ SP greaterThan
-- > evalT alwaysGreater ((5,1), [(0.001, (6, 1)), (0.001, (9, 2))])
-- True
eval1 = evalT alwaysGreater ((5,1), [(0.001, (6, 1)), (0.001, (9, 2))])
-- > evalT alwaysGreater ((1,5), [(0.001, (6, 1)), (0.001, (9, 2))])
-- False
eval2 = evalT alwaysGreater ((1,5), [(0.001, (6, 1)), (0.001, (9, 2))])
alwaysGreaterProperty :: Property
alwaysGreaterProperty = forAll arbitrary (evalT alwaysGreater)
evalQ1 = quickCheck alwaysGreaterProperty