Skip to content

Commit 8182e8e

Browse files
Merge branch 'release-0.13.0'. Refs #420.
2 parents a02df90 + 23289c6 commit 8182e8e

File tree

8 files changed

+171
-11
lines changed

8 files changed

+171
-11
lines changed

dunai-frp-bearriver/CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
2024-06-21 Ivan Perez <ivan.perez@keera.co.uk>
2+
* Version bump (0.14.9) (#420).
3+
* Offer all definitions from FRP.Yampa.Hybrid (#419).
4+
15
2024-04-23 Ivan Perez <ivan.perez@keera.co.uk>
26
* Version bump (0.14.8) (#411).
37
* Offer all definitions from FRP.Yampa.Loop (#407).

dunai-frp-bearriver/bearriver.cabal

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ cabal-version: >= 1.10
3030
build-type: Simple
3131

3232
name: bearriver
33-
version: 0.14.8
33+
version: 0.14.9
3434
author: Ivan Perez, Manuel Bärenz
3535
maintainer: ivan.perez@keera.co.uk
3636
homepage: https://github.com/ivanperez-keera/dunai
@@ -99,11 +99,11 @@ library
9999
build-depends:
100100
base >= 4.6 && <5
101101
, deepseq >= 1.3.0.0 && < 1.6
102-
, dunai >= 0.6.0 && < 0.13
102+
, dunai >= 0.6.0 && < 0.14
103103
, MonadRandom >= 0.2 && < 0.7
104104
, mtl >= 2.1.2 && < 2.3
105105
, simple-affine-space >= 0.1 && < 0.3
106-
, transformers >= 0.3 && < 0.6
106+
, transformers >= 0.3 && < 0.7
107107

108108
default-language:
109109
Haskell2010

dunai-frp-bearriver/src/FRP/BearRiver/Hybrid.hs

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,34 @@
66
-- Maintainer : ivan.perez@keera.co.uk
77
--
88
-- Discrete to continuous-time signal functions.
9-
module FRP.BearRiver.Hybrid where
9+
module FRP.BearRiver.Hybrid
10+
(
11+
-- * Wave-form generation
12+
hold
13+
, dHold
14+
, trackAndHold
15+
, dTrackAndHold
16+
17+
-- * Accumulators
18+
, accum
19+
, accumHold
20+
, dAccumHold
21+
, accumBy
22+
, accumHoldBy
23+
, dAccumHoldBy
24+
, accumFilter
25+
)
26+
where
1027

1128
-- External imports
12-
import Control.Arrow (arr, returnA, (<<<))
29+
import Control.Arrow (arr, returnA, (<<<), (>>>))
1330

1431
-- Internal imports (dunai)
1532
import Data.MonadicStreamFunction (accumulateWith, feedback)
1633

1734
-- Internal imports (bearriver)
1835
import FRP.BearRiver.Arrow (dup)
36+
import FRP.BearRiver.Delays (iPre)
1937
import FRP.BearRiver.Event (Event (..), event)
2038
import FRP.BearRiver.InternalCore (SF)
2139

@@ -36,8 +54,66 @@ hold :: Monad m => a -> SF m (Event a) a
3654
hold a = feedback a $ arr $ \(e, a') ->
3755
dup (event a' id e)
3856

57+
-- | Zero-order hold with a delay.
58+
--
59+
-- Converts a discrete-time signal into a continuous-time signal, by holding the
60+
-- last value until it changes in the input signal. The given parameter is used
61+
-- for time zero (until the first event occurs in the input signal), so 'dHold'
62+
-- shifts the discrete input by an infinitesimal delay.
63+
--
64+
-- >>> embed (dHold 1) (deltaEncode 0.1 [NoEvent, NoEvent, Event 2, NoEvent, Event 3, NoEvent])
65+
-- [1,1,1,2,2,3]
66+
dHold :: Monad m => a -> SF m (Event a) a
67+
dHold a0 = hold a0 >>> iPre a0
68+
69+
-- | Tracks input signal when available, holding the last value when the input
70+
-- is 'Nothing'.
71+
--
72+
-- This behaves similarly to 'hold', but there is a conceptual difference, as it
73+
-- takes a signal of input @Maybe a@ (for some @a@) and not @Event@.
74+
--
75+
-- >>> embed (trackAndHold 1) (deltaEncode 0.1 [Nothing, Nothing, Just 2, Nothing, Just 3, Nothing])
76+
-- [1,1,2,2,3,3]
77+
trackAndHold :: Monad m => a -> SF m (Maybe a) a
78+
trackAndHold aInit = arr (maybe NoEvent Event) >>> hold aInit
79+
80+
-- | Tracks input signal when available, holding the last value when the input
81+
-- is 'Nothing', with a delay.
82+
--
83+
-- This behaves similarly to 'hold', but there is a conceptual difference, as it
84+
-- takes a signal of input @Maybe a@ (for some @a@) and not @Event@.
85+
--
86+
-- >>> embed (dTrackAndHold 1) (deltaEncode 0.1 [Nothing, Nothing, Just 2, Nothing, Just 3, Nothing])
87+
-- [1,1,1,2,2,3]
88+
dTrackAndHold :: Monad m => a -> SF m (Maybe a) a
89+
dTrackAndHold aInit = trackAndHold aInit >>> iPre aInit
90+
3991
-- ** Accumulators
4092

93+
-- | Given an initial value in an accumulator, it returns a signal function that
94+
-- processes an event carrying transformation functions. Every time an 'Event'
95+
-- is received, the function inside it is applied to the accumulator, whose new
96+
-- value is outputted in an 'Event'.
97+
accum :: Monad m => a -> SF m (Event (a -> a)) (Event a)
98+
accum aInit = feedback aInit $ arr $ \(f, a) -> case f of
99+
NoEvent -> (NoEvent, a)
100+
Event f' -> let a' = f' a
101+
in (Event a', a')
102+
103+
-- | Zero-order hold accumulator (always produces the last outputted value until
104+
-- an event arrives).
105+
accumHold :: Monad m => a -> SF m (Event (a -> a)) a
106+
accumHold aInit = feedback aInit $ arr $ \(f, a) -> case f of
107+
NoEvent -> (a, a)
108+
Event f' -> let a' = f' a
109+
in (a', a')
110+
111+
-- | Zero-order hold accumulator with delayed initialization (always produces
112+
-- the last outputted value until an event arrives, but the very initial output
113+
-- is always the given accumulator).
114+
dAccumHold :: Monad m => a -> SF m (Event (a -> a)) a
115+
dAccumHold aInit = accumHold aInit >>> iPre aInit
116+
41117
-- | Accumulator parameterized by the accumulation function.
42118
accumBy :: Monad m => (b -> a -> b) -> b -> SF m (Event a) (Event b)
43119
accumBy f b = mapEventS $ accumulateWith (flip f) b
@@ -48,6 +124,25 @@ accumHoldBy f b = feedback b $ arr $ \(a, b') ->
48124
let b'' = event b' (f b') a
49125
in (b'', b'')
50126

127+
-- | Zero-order hold accumulator parameterized by the accumulation function with
128+
-- delayed initialization (initial output sample is always the given
129+
-- accumulator).
130+
dAccumHoldBy :: Monad m => (b -> a -> b) -> b -> SF m (Event a) b
131+
dAccumHoldBy f aInit = accumHoldBy f aInit >>> iPre aInit
132+
133+
-- | Accumulator parameterized by the accumulator function with filtering,
134+
-- possibly discarding some of the input events based on whether the second
135+
-- component of the result of applying the accumulation function is 'Nothing' or
136+
-- 'Just' x for some x.
137+
accumFilter :: Monad m
138+
=> (c -> a -> (c, Maybe b)) -> c -> SF m (Event a) (Event b)
139+
accumFilter g cInit = feedback cInit $ arr $ \(a, c) ->
140+
case a of
141+
NoEvent -> (NoEvent, c)
142+
Event a' -> case g c a' of
143+
(c', Nothing) -> (NoEvent, c')
144+
(c', Just b) -> (Event b, c')
145+
51146
-- * Events
52147

53148
-- | Apply an 'SF' to every input. Freezes temporarily if the input is

dunai-test/CHANGELOG

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2024-06-21 Ivan Perez <ivan.perez@keera.co.uk>
2+
* Version bump (0.13.0) (#420).
3+
14
2024-04-23 Ivan Perez <ivan.perez@keera.co.uk>
25
* Version bump (0.12.3) (#411).
36

dunai-test/dunai-test.cabal

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ cabal-version: >= 1.10
3030
build-type: Simple
3131

3232
name: dunai-test
33-
version: 0.12.3
33+
version: 0.13.0
3434
author: Ivan Perez
3535
maintainer: ivan.perez@keera.co.uk
3636
homepage: https://github.com/ivanperez-keera/dunai
@@ -77,7 +77,7 @@ library
7777

7878
build-depends:
7979
base >= 4 && < 5
80-
, dunai >= 0.5 && < 0.13
80+
, dunai >= 0.5 && < 0.14
8181
, normaldistribution >= 1.0 && < 1.2
8282
, QuickCheck >= 2.12 && < 2.15
8383

dunai/CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
2024-06-21 Ivan Perez <ivan.perez@keera.co.uk>
2+
* Version bump (0.13.0) (#420).
3+
* Implement List interface using list-transformer (#418).
4+
15
2024-04-23 Ivan Perez <ivan.perez@keera.co.uk>
26
* Version bump (0.12.3) (#411).
37
* Fix typo in documentation (#410).

dunai/dunai.cabal

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ cabal-version: >= 1.10
3030
build-type: Simple
3131

3232
name: dunai
33-
version: 0.12.3
33+
version: 0.13.0
3434
author: Ivan Perez, Manuel Bärenz
3535
maintainer: ivan.perez@keera.co.uk
3636
homepage: https://github.com/ivanperez-keera/dunai
@@ -97,6 +97,10 @@ flag test-doc-coverage
9797
default: False
9898
manual: True
9999

100+
flag list-transformer
101+
description: Use list-transformer instead of transformers to implement the ListT combinators
102+
default: False
103+
100104

101105
library
102106
exposed-modules:
@@ -147,6 +151,13 @@ library
147151
, transformers-compat >= 0.3 && < 0.8
148152
, void >= 0.1 && < 0.8
149153

154+
if flag(list-transformer)
155+
build-depends:
156+
list-transformer >= 1.1.1 && < 1.2
157+
, transformers >= 0.3 && < 0.7
158+
159+
cpp-options: -DLIST_TRANSFORMER
160+
150161
test-suite hlint
151162
type:
152163
exitcode-stdio-1.0

dunai/src/Control/Monad/Trans/MSF/List.hs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@
2626
-- additional constraints on the inner monad in order for the combination of
2727
-- the monad and the transformer to be a monad. Use at your own risk.
2828
module Control.Monad.Trans.MSF.List
29-
{-# WARNING "This module uses the ListT transformer, which is considered deprecated." #-}
3029
( module Control.Monad.Trans.MSF.List
31-
, module Control.Monad.Trans.List
30+
, module List
3231
)
3332
where
3433

@@ -37,13 +36,54 @@ module Control.Monad.Trans.MSF.List
3736
import Control.Applicative ((<$>))
3837
#endif
3938

40-
import Control.Monad.Trans.List hiding (liftCallCC, liftCatch)
39+
#ifdef LIST_TRANSFORMER
40+
import Control.Monad (sequence)
41+
import List.Transformer (ListT (ListT, next), Step (..), fold, select)
42+
import qualified List.Transformer as List
43+
#else
44+
import Control.Monad.Trans.List as List hiding (liftCallCC, liftCatch)
45+
#endif
4146

4247
-- Internal imports
4348
import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))
4449

4550
-- * List monad
4651

52+
#ifdef LIST_TRANSFORMER
53+
54+
-- | Run an 'MSF' in the 'ListT' transformer (i.e., multiple MSFs producing
55+
-- each producing one output), by applying the input stream to each MSF in the
56+
-- list transformer and concatenating the outputs of the MSFs together.
57+
--
58+
-- An MSF in the ListT transformer can spawn into more than one MSF, or none,
59+
-- so the outputs produced at each individual step are not guaranteed to all
60+
-- have the same length.
61+
widthFirst :: (Functor m, Monad m) => MSF (ListT m) a b -> MSF m a [b]
62+
widthFirst msf = widthFirst' [msf]
63+
where
64+
widthFirst' msfs = MSF $ \a -> do
65+
(bs, msfs') <- unzip . concat <$> mapM (toList . flip unMSF a) msfs
66+
return (bs, widthFirst' msfs')
67+
68+
toList :: (Functor m, Monad m) => ListT m a -> m [a]
69+
toList = fmap reverse . fold (flip (:)) [] id
70+
71+
-- | Build an 'MSF' in the 'ListT' transformer by broadcasting the input stream
72+
-- value to each MSF in a given list.
73+
sequenceS :: Monad m => [MSF m a b] -> MSF (ListT m) a b
74+
sequenceS msfs = MSF $ \a -> sequence' $ apply a <$> msfs
75+
where
76+
sequence' :: Monad m => [m a] -> ListT m a
77+
sequence' xs = ListT $ next <$> select =<< sequence xs
78+
79+
apply :: Monad m => a -> MSF m a b -> m (b, MSF (ListT m) a b)
80+
apply a msf = do
81+
(b, msf') <- unMSF msf a
82+
return (b, sequenceS [msf'])
83+
84+
#else
85+
86+
{-# DEPRECATED widthFirst "This ListT definition is deprecated. Use the list-transformer variant of this function instead." #-}
4787
-- | Run an 'MSF' in the 'ListT' transformer (i.e., multiple MSFs producing
4888
-- each producing one output), by applying the input stream to each MSF in the
4989
-- list transformer and concatenating the outputs of the MSFs together.
@@ -58,6 +98,7 @@ widthFirst msf = widthFirst' [msf]
5898
(bs, msfs') <- unzip . concat <$> mapM (runListT . flip unMSF a) msfs
5999
return (bs, widthFirst' msfs')
60100

101+
{-# DEPRECATED sequenceS "This ListT definition is deprecated. Use the list-transformer variant of this function instead." #-}
61102
-- | Build an 'MSF' in the 'ListT' transformer by broadcasting the input stream
62103
-- value to each MSF in a given list.
63104
sequenceS :: Monad m => [MSF m a b] -> MSF (ListT m) a b
@@ -67,6 +108,8 @@ sequenceS msfs = MSF $ \a -> ListT $ sequence $ apply a <$> msfs
67108
(b, msf') <- unMSF msf a
68109
return (b, sequenceS [msf'])
69110

111+
#endif
112+
70113
-- | Apply an 'MSF' to every input.
71114
mapMSF :: Monad m => MSF m a b -> MSF m [a] [b]
72115
mapMSF = MSF . consume

0 commit comments

Comments
 (0)