Skip to content

Commit fac2cb1

Browse files
committed
fix frequency
1 parent c17dc11 commit fac2cb1

File tree

5 files changed

+95
-7
lines changed

5 files changed

+95
-7
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ install:
1414
- bower install
1515
script:
1616
- npm run -s build
17+
- npm run -s test
1718
after_success:
1819
- >-
1920
test $TRAVIS_TAG &&

bower.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,12 @@
2121
"purescript-tuples": "^4.0.0",
2222
"purescript-unfoldable": "^3.0.0",
2323
"purescript-integers": "^3.0.0"
24+
},
25+
"devDependencies": {
26+
"purescript-console": "^3.0.0",
27+
"purescript-assert": "^3.0.0",
28+
"purescript-arrays": "^4.2.1",
29+
"purescript-transformers": "^3.4.0",
30+
"purescript-math": "^2.1.0"
2431
}
2532
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"private": true,
33
"scripts": {
44
"clean": "rimraf output && rimraf .pulp-cache",
5+
"test": "pulp test",
56
"build": "pulp build -- --censor-lib --strict"
67
},
78
"devDependencies": {

src/Control/Monad/Gen.purs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import Control.Monad.Gen.Class (class MonadGen, Size, chooseBool, chooseFloat, c
1414
import Control.Monad.Rec.Class (class MonadRec, Step(..), tailRecM)
1515

1616
import Data.Foldable (class Foldable, length, foldl, foldMap)
17-
import Data.Int as Int
1817
import Data.Maybe (Maybe(..), fromMaybe)
1918
import Data.Monoid.Additive (Additive(..))
2019
import Data.Newtype (alaF)
@@ -46,15 +45,26 @@ frequency
4645
=> Foldable f
4746
=> NonEmpty f (Tuple Number (m a))
4847
-> m a
49-
frequency (x :| xs) =
48+
frequency (x :| xs) =
5049
let
5150
first = fst x
5251
total = first + alaF Additive foldMap fst xs
53-
in do
54-
pos <- chooseFloat 0.0 total
55-
let n = Int.round (pos / total * length xs)
56-
snd $ if n == 0 then x else fromIndex (n - 1) x xs
57-
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
5868
-- | Creates a generator that outputs a value chosen from a selection with
5969
-- | uniform probability.
6070
elements :: forall m f a. MonadGen m => Foldable f => NonEmpty f a -> m a

test/Test/Main.purs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
module Test.Main where
2+
3+
import Prelude
4+
5+
import Test.Assert (ASSERT, assert)
6+
import Partial.Unsafe (unsafeCrashWith)
7+
import Control.Monad.Eff (Eff)
8+
import Control.Monad.Eff.Console (CONSOLE, log)
9+
import Control.Monad.Gen (class MonadGen, frequency)
10+
import Data.NonEmpty ((:|), NonEmpty(..))
11+
import Data.Traversable (sequence)
12+
import Data.Array (replicate, group', length)
13+
import Data.Tuple (Tuple(..))
14+
import Data.Newtype (unwrap)
15+
import Math (remainder)
16+
import Control.Monad.State (State, class MonadState, get, put, evalStateT)
17+
18+
type TestEffects = (console :: CONSOLE, assert :: ASSERT)
19+
type Tests = Eff TestEffects Unit
20+
21+
newtype TestGen a = TestGen (State Number a)
22+
derive newtype instance testGenFunctor :: Functor TestGen
23+
derive newtype instance testGenApply :: Apply TestGen
24+
derive newtype instance testGenBind :: Bind TestGen
25+
derive newtype instance testGenApplicative :: Applicative TestGen
26+
derive newtype instance testGenMonad :: Monad TestGen
27+
derive newtype instance testGenMonadState :: MonadState Number TestGen
28+
29+
instance testGenMonadGen :: MonadGen TestGen where
30+
sized _ = unsafeCrashWith "sized should not be called"
31+
resize _ _ = unsafeCrashWith "resize should not be called"
32+
chooseBool = pure unit >>= \_ -> unsafeCrashWith "chooseBool should not be called"
33+
chooseFloat s e = do
34+
c <- get
35+
put (c + 1.0)
36+
pure ((s + c) `remainder` e)
37+
chooseInt _ _ = unsafeCrashWith "chooseFloat should not be called"
38+
39+
runTestGen :: TestGen ~> State Number
40+
runTestGen (TestGen x) = x
41+
42+
main :: Tests
43+
main = do
44+
log "check frequency"
45+
let
46+
abcGen :: TestGen String
47+
abcGen =
48+
frequency $
49+
( Tuple 10.0 $ pure "A" ) :|
50+
[ Tuple 20.0 $ pure "B"
51+
, Tuple 0.0 $ pure "Z"
52+
, Tuple 30.0 $ pure "C"
53+
, Tuple 40.0 $ pure "D"
54+
, Tuple 50.0 $ pure "E"
55+
, Tuple 50.0 $ pure "F"
56+
]
57+
abcArrGen = sequence $ replicate 200 abcGen
58+
abcArr = runTestGen abcArrGen `evalStateT` 0.0 # unwrap
59+
actual = group' abcArr
60+
<#> \(NonEmpty x xs) -> Tuple (length xs + 1) x
61+
expected =
62+
[ (Tuple 10 "A")
63+
, (Tuple 20 "B")
64+
, (Tuple 30 "C")
65+
, (Tuple 40 "D")
66+
, (Tuple 50 "E")
67+
, (Tuple 50 "F")
68+
]
69+
assert (expected == actual)

0 commit comments

Comments
 (0)