@@ -12,12 +12,11 @@ import Prelude
12
12
13
13
import Control.Monad.Gen.Class (class MonadGen , Size , chooseBool , chooseFloat , chooseInt , resize , sized )
14
14
import Control.Monad.Rec.Class (class MonadRec , Step (..), tailRecM )
15
-
16
- import Data.Foldable (class Foldable , length , foldl , foldMap )
17
- import Data.Maybe (Maybe (..), fromMaybe )
15
+ import Data.Foldable (foldMap , length )
16
+ import Data.Maybe (Maybe (..))
18
17
import Data.Monoid.Additive (Additive (..))
19
18
import Data.Newtype (alaF )
20
- import Data.NonEmpty ( NonEmpty , (:|) )
19
+ import Data.Semigroup.Foldable ( class Foldable1 , foldMap1 )
21
20
import Data.Tuple (Tuple (..), fst , snd )
22
21
import Data.Unfoldable (class Unfoldable , unfoldr )
23
22
@@ -30,10 +29,29 @@ choose genA genB = chooseBool >>= if _ then genA else genB
30
29
31
30
-- | Creates a generator that outputs a value chosen from a selection of
32
31
-- | existing generators with uniform probability.
33
- oneOf :: forall m f a . MonadGen m => Foldable f => NonEmpty f (m a ) -> m a
34
- oneOf (x :| xs) = do
35
- n <- chooseInt 0 (length xs)
36
- if n < 1 then x else fromIndex (n - 1 ) x xs
32
+ oneOf :: forall m f a . MonadGen m => Foldable1 f => f (m a ) -> m a
33
+ oneOf xs = do
34
+ n <- chooseInt 0 (length xs - 1 )
35
+ fromIndex n xs
36
+
37
+ newtype FreqSemigroup a = FreqSemigroup (Number -> Tuple (Maybe Number ) a )
38
+
39
+ freqSemigroup :: forall a . Tuple Number a -> FreqSemigroup a
40
+ freqSemigroup (Tuple weight x) =
41
+ FreqSemigroup \pos ->
42
+ if pos >= weight
43
+ then Tuple (Just (pos - weight)) x
44
+ else Tuple Nothing x
45
+
46
+ getFreqVal :: forall a . FreqSemigroup a -> Number -> a
47
+ getFreqVal (FreqSemigroup f) = snd <<< f
48
+
49
+ instance semigroupFreqSemigroup :: Semigroup (FreqSemigroup a ) where
50
+ append (FreqSemigroup f) (FreqSemigroup g) =
51
+ FreqSemigroup \pos ->
52
+ case f pos of
53
+ Tuple (Just pos') _ -> g pos'
54
+ result -> result
37
55
38
56
-- | Creates a generator that outputs a value chosen from a selection of
39
57
-- | existing generators, where the selection has weight values for the
@@ -42,35 +60,19 @@ oneOf (x :| xs) = do
42
60
frequency
43
61
:: forall m f a
44
62
. MonadGen m
45
- => Foldable f
46
- => NonEmpty f (Tuple Number (m a ))
63
+ => Foldable1 f
64
+ => f (Tuple Number (m a ))
47
65
-> m a
48
- frequency (x :| xs) =
49
- let
50
- first = fst x
51
- total = first + alaF Additive foldMap fst xs
52
- in
53
- chooseFloat 0.0 total >>= pick
54
- where
55
- pick pos =
56
- let
57
- initial = go (Tuple 0.0 $ snd x) x
58
- in
59
- snd $ foldl go initial xs
60
- where
61
- go (Tuple weight val) (Tuple currWeight currVal) =
62
- let
63
- nextWeight = weight + currWeight
64
- in
65
- if weight <= pos && pos <= nextWeight
66
- then Tuple nextWeight currVal
67
- else Tuple nextWeight val
66
+ frequency xs =
67
+ let total = alaF Additive foldMap fst xs
68
+ in chooseFloat 0.0 total >>= getFreqVal (foldMap1 freqSemigroup xs)
69
+
68
70
-- | Creates a generator that outputs a value chosen from a selection with
69
71
-- | uniform probability.
70
- elements :: forall m f a . MonadGen m => Foldable f => NonEmpty f a -> m a
71
- elements (x :| xs) = do
72
- n <- chooseInt 0 (length xs)
73
- pure if n == 0 then x else fromIndex (n - 1 ) x xs
72
+ elements :: forall m f a . MonadGen m => Foldable1 f => f a -> m a
73
+ elements xs = do
74
+ n <- chooseInt 0 (length xs - 1 )
75
+ pure $ fromIndex n xs
74
76
75
77
-- | Creates a generator that produces unfoldable structures based on an
76
78
-- | existing generator for the elements.
@@ -115,7 +117,22 @@ filtered gen = tailRecM go unit
115
117
Nothing -> Loop unit
116
118
Just a' -> Done a'
117
119
118
- fromIndex :: forall f a . Foldable f => Int -> a -> f a -> a
119
- fromIndex i a = fromMaybe a <<< snd <<< (foldl go (Tuple 0 (Just a)))
120
+ -- | Internal: used by fromIndex
121
+ newtype AtIndex a = AtIndex (Int -> a )
122
+
123
+ instance semigroupAtIndex :: Semigroup (AtIndex a )
120
124
where
121
- go (Tuple ix v) x = Tuple (ix + 1 ) (if ix == i then Just x else v)
125
+ append (AtIndex f) (AtIndex g) =
126
+ AtIndex \i -> if i <= 0 then f i else g (i - 1 )
127
+
128
+ atIndex :: forall a . a -> AtIndex a
129
+ atIndex = AtIndex <<< const
130
+
131
+ getAtIndex :: forall a . AtIndex a -> Int -> a
132
+ getAtIndex (AtIndex f) = f
133
+
134
+ -- | Internal: get the Foldable element at index i.
135
+ -- | If the index is <= 0, return the first element.
136
+ -- | If it's >= length, return the last.
137
+ fromIndex :: forall f a . Foldable1 f => Int -> f a -> a
138
+ fromIndex i xs = getAtIndex (foldMap1 atIndex xs) i
0 commit comments