{-# OPTIONS --type-in-type --no-termination-check #-}
module UFRP where
open import NeilPrelude
open import List
open import RealTime renaming (_₀>=₀_ to _>=_ ; _₀>₀_ to _>_ ; _₀<₀_ to _<_)
open import Real hiding (_-_ ; _>=_)
open import StrictTotalOrder hiding (_>_ ; _<_)
open import Bool renaming (_∧_ to _&&_ ; _∨_ to _||_)
Signal : Set → Set
Signal A = Time → A
SF : Set → Set → Set
SF A B = Signal A → Signal B
Event : Set → Set
Event A = List (Time × A)
constant : {A B : Set} → B → SF A B
constant b = λ s t → b
lift : {A B : Set} → (A → B) → SF A B
lift f = λ s → f ∘ s
notYet : {A : Set} → SF (Event A) (Event A)
notYet = λ s → dropWhile (_>=_ O ∘ fst) ∘ s
postulate when : {A : Set} → (A → Bool) → SF A (Event A)
postulate integral : SF ℜ ℜ
infixr 90 _>>>_
infixr 91 _&&&_
_>>>_ : {A B C : Set} → SF A B → SF B C → SF A C
sf₁ >>> sf₂ = sf₂ ∘ sf₁
_&&&_ : {A B C : Set} → SF A B → SF A C → SF A (B × C)
sf₁ &&& sf₂ = λ s t → (sf₁ s t , sf₂ s t)
private
postulate ≤-trustme : {te : EventTime} → {t : SampleTime} → te ≤ℜ₀ t
_-_ : (t : SampleTime) → (te : EventTime) → Time
t - te = ℜ₀-minus t te ≤-trustme
advance : {A : Set} → Time → Signal A → Signal A
advance d s t = s (t ₀+₀ d)
splice : {A : Set} → Signal A → Signal A → Time → Signal A
splice s₁ s₂ tx t with compareGeqℜ₀ t tx
... | less p = s₁ t
... | geq p = s₂ (ℜ₀-minus t tx p)
switch : {A B E : Set} → SF A (B × Event E) → (E → SF A B) → SF A B
switch {A} sf f s t with sf s t
... | (b , ev) with dropWhile (λ tee → fst tee < O) ev
... | [] = b
... | (te , e) ∷ _ = (f e) (advance te s) (t - te)
dswitch : {A B E : Set} → SF A (B × Event E) → (E → SF A B) → SF A B
dswitch {A} sf f s t with sf s t
... | (b , ev) with dropWhile (λ tee → fst tee < O || fst tee >= t) ev
... | [] = b
... | (te , e) ∷ _ = (f e) (advance te s) (t - te)
freeze : {A B : Set} → SF A B → SF A (B × SF A B)
freeze sf = λ s t → (sf s t , λ s' → advance t (sf (splice s s' t)))
iIntegral : ℜ → SF ℜ ℜ
iIntegral x = integral >>> lift (_+_ x)
identity : {A : Set} → SF A A
identity = lift id
sfFst : {A B : Set} → SF (A × B) A
sfFst = lift fst
sfSnd : {A B : Set} → SF (A × B) B
sfSnd = lift snd
sfSwap : {A B : Set} → SF (A × B) (B × A)
sfSwap = lift swap
sfFork : {A : Set} → SF A (A × A)
sfFork = lift fork
toFst : {A B C : Set} → SF A C → SF (A × B) C
toFst sf = sfFst >>> sf
toSnd : {A B C : Set} → SF B C → SF (A × B) C
toSnd sf = sfSnd >>> sf
_***_ : {A B C D : Set} → SF A C → SF B D → SF (A × B) (C × D)
sf₁ *** sf₂ = toFst sf₁ &&& toSnd sf₂
sfFirst : {A B C : Set} → SF A B → SF (A × C) (B × C)
sfFirst sf = sf *** identity
sfSecond : {A B C : Set} → SF B C → SF (A × B) (A × C)
sfSecond sf = identity *** sf
forkFirst : {A B : Set} → SF A B → SF A (B × A)
forkFirst sf = sfFork >>> sfFirst sf
forkSecond : {A B : Set} → SF A B → SF A (A × B)
forkSecond sf = sfFork >>> sfSecond sf
switchWhen : {A B E : Set} → SF A B → SF B (Event E) → (E → SF A B) → SF A B
switchWhen sf sfe = switch (sf >>> forkSecond sfe)
rswitch : {A B E : Set} → SF A (B × Event E) → (E → SF A (B × Event E)) → SF A B
rswitch sf f = switch sf (λ e → rswitch (f e >>> sfSecond notYet) f)
rswitchWhen : {A B E : Set} → SF A B → SF B (Event E) → (E → SF A B) → SF A B
rswitchWhen sf sfe f = rswitch (sf >>> forkSecond sfe) (λ e → f e >>> forkSecond sfe)
replace : {A B E : Set} → SF A B → (E → SF A B) → SF (A × Event E) B
replace sf f = rswitch (sfFirst sf) (λ e → sfFirst (f e))
open import BouncingBall
fallingBall : {A : Set} → Ball → SF A Ball
fallingBall (h , v) = constant (negate g) >>> iIntegral v >>> forkFirst (iIntegral h)
detectBounce : SF Ball (Event Ball)
detectBounce = when detectImpact
elasticBall : {A : Set} → Ball → SF A Ball
elasticBall b = rswitchWhen (fallingBall b) detectBounce (fallingBall ∘ negateVel)
inelasticBall : {A : Set} → Ball → SF A Ball
inelasticBall b = switchWhen (fallingBall b) detectBounce (λ _ → constant (O , O))
resetBall : {A : Set} → (Ball → SF A Ball) → Ball → SF (A × Event Ball) Ball
resetBall f b = replace (f b) f
initialise : {A : Set} → A → Signal A → Signal A
initialise a s O = a
initialise a s (t >0) = s (t >0)