File: Move.hs

package info (click to toggle)
haskell-netwire 5.0.3-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 184 kB
  • sloc: haskell: 1,326; makefile: 2
file content (77 lines) | stat: -rw-r--r-- 2,071 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
-- |
-- Module:     FRP.Netwire.Move
-- Copyright:  (c) 2013 Ertugrul Soeylemez
-- License:    BSD3
-- Maintainer: Ertugrul Soeylemez <es@ertes.de>

module FRP.Netwire.Move
    ( -- * Calculus
      derivative,
      integral,
      integralWith
    )
    where

import Control.Wire


-- | Time derivative of the input signal.
--
-- * Depends: now.
--
-- * Inhibits: at singularities.

derivative ::
    (RealFloat a, HasTime t s, Monoid e)
    => Wire s e m a a
derivative = mkPure $ \_ x -> (Left mempty, loop x)
    where
    loop x' =
        mkPure $ \ds x ->
            let dt  = realToFrac (dtime ds)
                dx  = (x - x') / dt
                mdx | isNaN dx      = Right 0
                    | isInfinite dx = Left mempty
                    | otherwise     = Right dx
            in mdx `seq` (mdx, loop x)


-- | Integrate the input signal over time.
--
-- * Depends: before now.

integral ::
    (Fractional a, HasTime t s)
    => a  -- ^ Integration constant (aka start value).
    -> Wire s e m a a
integral x' =
    mkPure $ \ds dx ->
        let dt = realToFrac (dtime ds)
        in x' `seq` (Right x', integral (x' + dt*dx))


-- | Integrate the left input signal over time, but apply the given
-- correction function to it.  This can be used to implement collision
-- detection/reaction.
--
-- The right signal of type @w@ is the /world value/.  It is just passed
-- to the correction function for reference and is not used otherwise.
--
-- The correction function must be idempotent with respect to the world
-- value: @f w (f w x) = f w x@.  This is necessary and sufficient to
-- protect time continuity.
--
-- * Depends: before now.

integralWith ::
    (Fractional a, HasTime t s)
    => (w -> a -> a)  -- ^ Correction function.
    -> a              -- ^ Integration constant (aka start value).
    -> Wire s e m (a, w) a
integralWith correct = loop
    where
    loop x' =
        mkPure $ \ds (dx, w) ->
            let dt = realToFrac (dtime ds)
                x  = correct w (x' + dt*dx)
            in x' `seq` (Right x', loop x)