<commit_before>{-# LANGUAGE OverloadedStrings #-}
module Generator(generator, Generator(..), GeneratorDelay) where

  import System.Random
  import Control.Monad
  import Data.Attoparsec 
  import Control.Applicative ((<$>))
  import qualified Data.Attoparsec.Char8 as C
  import qualified Data.ByteString.Char8 as B

  -- |Function that delays the generator for the given number of microseconds.
  --  A suitable value is @threadDelay@
  type GeneratorDelay = Int -> IO ()

  -- |This will need thinking...
  type GeneratorResult a = IO a

  -- |Generator is a type that performs a step of the generation process
  newtype Generator a = Generator { 

    -- |Performs the generator step
    runGenerator :: GeneratorDelay     -- ^The delaying function. You can pass in @threadDelay@, for example.
                 -> GeneratorResult a  -- ^The step result
  }

  -- evendistr 10 [0..100] 
  -- evendistr 10 [0..100] 5 times
  -- evendistr 10 [0..100] [0..5] times
  -- evendistr 10 [0..100] forever 
  -- evendistr 10 [0..100] ... every 1000ms
  -- evendistr 10 [0..100] ... every [1000..2000]ms

  -- |Prepares a generator by parsing the input string. It returns a value that
  --  you can use to get the generated values.
  --   
  --  Typically, you'd have code similar to
  --  @
  --      case (generator "evendistr 5 [1..2] every 50ms") of
  --          Left err  -> ...                                  -- what do you want, a cookie?
  --          Right gen -> runGenerator gen threadDelay >>= ... -- good user, have numbers
  -- @
  -- In GHCi, you can try out
  -- @
  --     let (Right nums) = (runGenerator) <$> generator ("evendistr 5 [1..2] every 50ms")
  -- @
  generator :: String                           -- ^The expression to parse
            -> Either String (Generator [Int])  -- ^The result with errors or the ready Generator
  generator input = do
    expr <- parseOnly expression (B.pack input)
    return $ runGenerator expr
    where
      runGenerator :: Expression -> Generator [Int]
      -- TODO: complete the Times repetition
      runGenerator (Expression (EvenDistr countRange valueRange) _ (Fixed delayRange)) = Generator { 
        runGenerator = \wait -> do
          count <- fromRange countRange
          delay <- fromRange delayRange
          wait delay
          replicateM count (fromRange valueRange)
      }
      fromRange :: Range -> IO Int
      fromRange (Exact x) = return x
      fromRange (Between l u) = ((l +) . (`mod` (u - l)) <$> (randomIO :: IO Int))

  -- |Range is either a single value or between some upper and lower limit
  data Range = 
      -- |Exact value
      Exact Int 
      -- |Value between lower and upper limit; lower < upper.
    | Between Int Int deriving (Show)<commit_msg>Comments<commit_after>{-# LANGUAGE OverloadedStrings #-}
module Generator(generator, Generator(..), GeneratorDelay) where

  import System.Random
  import Control.Monad
  import Data.Attoparsec 
  import Control.Applicative ((<$>))
  import qualified Data.Attoparsec.Char8 as C
  import qualified Data.ByteString.Char8 as B

  -- |Function that delays the generator for the given number of microseconds.
  --  A suitable value is @threadDelay@
  type GeneratorDelay = Int -> IO ()

  -- |This will need thinking...
  type GeneratorResult a = IO a

  -- |Generator is a type that performs a step of the generation process
  newtype Generator a = Generator { 

    -- |Performs the generator step
    runGenerator :: GeneratorDelay     -- ^The delaying function. You can pass in @threadDelay@, for example.
                 -> GeneratorResult a  -- ^The step result
  }

  -- evendistr 10 [0..100] 
  -- evendistr 10 [0..100] 5 times
  -- evendistr 10 [0..100] [0..5] times
  -- evendistr 10 [0..100] forever 
  -- evendistr 10 [0..100] ... every 1000ms
  -- evendistr 10 [0..100] ... every [1000..2000]ms

  -- |Prepares a generator by parsing the input string. It returns a value that
  --  you can use to get the generated values.
  --   
  --  Typically, you'd have code similar to
  --  @
  --      case (generator "evendistr 5 [1..2] every 50ms") of
  --          Left err  -> ...                                  -- what do you want, a cookie?
  --          Right gen -> runGenerator gen threadDelay >>= ... -- good user, have numbers
  -- @
  -- In GHCi, you can try out
  -- @
  --     let (Right nums) = (runGenerator) <$> generator ("evendistr 5 [1..2] every 50ms")
  --     nums (const $ return ())
  --     -- or, if you have import Control.Concurrent (threadDelay)
  --     nums threadDelay
  -- @
  generator :: String                           -- ^The expression to parse
            -> Either String (Generator [Int])  -- ^The result with errors or the ready Generator
  generator input = do
    expr <- parseOnly expression (B.pack input)
    return $ runGenerator expr
    where
      runGenerator :: Expression -> Generator [Int]
      -- TODO: complete the Times repetition
      runGenerator (Expression (EvenDistr countRange valueRange) _ (Fixed delayRange)) = Generator { 
        runGenerator = \wait -> do
          count <- fromRange countRange
          delay <- fromRange delayRange
          wait delay
          replicateM count (fromRange valueRange)
      }
      fromRange :: Range -> IO Int
      fromRange (Exact x) = return x
      fromRange (Between l u) = ((l +) . (`mod` (u - l)) <$> (randomIO :: IO Int))

  -- |Range is either a single value or between some upper and lower limit
  data Range = 
      -- |Exact value
      Exact Int 
      -- |Value between lower and upper limit; lower < upper.
    | Between Int Int deriving (Show)
{'fraction_non_alphanumeric': 0.11004444444444444, 'fraction_numerical': 0.0224, 'mean_word_length': 2.146532438478747, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6574895', 'n_tokens_mistral': 1723, 'n_tokens_neox': 1598, 'n_words': 613}