Last active
August 28, 2024 02:46
-
-
Save jeovazero/bf59edd5a228dc47e90742801c9e064b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE OverloadedRecordDot #-} | |
import System.Random | |
import System.Environment | |
import qualified Data.Set as S | |
import Text.Read | |
import Control.Category ((>>>)) | |
main = | |
getArgs >>= ((\args -> parse args >>= validate) >>> evaluate) | |
-- | |
-- Domain | |
-- | |
data Command = Command { quantity :: Int, size :: Int, maxnum :: Int } deriving (Eq, Show) | |
defaultCommand = Command 1 15 25 | |
data Failure = SyntaxError String String | Invalid String String deriving (Eq, Show) | |
type Result a = Either Failure a | |
ok a = Right a | |
failure f = Left f | |
type CliArgs = [String] | |
-- | |
-- Parser | |
-- | |
parse :: CliArgs -> Result Command | |
parse args = parsePairs defaultCommand args | |
parsePairs :: Command -> CliArgs -> Result Command | |
parsePairs command [] = ok command | |
parsePairs _ (x:[]) = failure $ SyntaxError "UnexpectedToken" x | |
parsePairs command (a:b:xs) = command' >>= (\c -> parsePairs c xs) | |
where | |
valueAsInt = parseAsInt b | |
command' = | |
case a of | |
"--quantity" -> fmap (\int -> command{quantity = int}) valueAsInt | |
"--size" -> fmap (\int -> command{size = int}) valueAsInt | |
"--maxnum" -> fmap (\int -> command{maxnum = int}) valueAsInt | |
unknown -> failure $ SyntaxError "UnknownCommand" unknown | |
parseAsInt :: String -> Result Int | |
parseAsInt x = | |
case readMaybe x of | |
Just v -> ok v | |
Nothing -> failure $ SyntaxError "NotANumber" x | |
-- | |
-- Validation | |
-- | |
validate command = | |
if command.maxnum < command.size || command.maxnum < 1 | |
then failure $ Invalid "field maxnum" "must be maxnum >= size and maxnum >= 1" | |
else ok command | |
-- | |
-- Eval | |
-- | |
evaluate (Right command) = do | |
print command | |
let randomNumbers = repeat (randomRIO (1,command.maxnum)) | |
r <- sequence | |
$ take command.quantity | |
$ repeat | |
$ takeM command.size S.empty randomNumbers | |
printList r | |
evaluate (Left f) = do | |
print f | |
putStr "\n" | |
putStrLn usage | |
usage = | |
unlines [ | |
"Usage: cli --quantity <q> --size <s> --maxnum <m>\n", | |
"Generates a specified number of lists with random numbers.\n", | |
"Options:", | |
" --quantity <q> Specify the number of lists to generate (integer).", | |
" --size <s> Specify the size of each list (integer).", | |
" --maxnum <m> Set the maximum number for generated numbers (integer). The range will be [1, maxnum].\n", | |
"Example:", | |
" cli --quantity 5 --size 10 --maxnum 100", | |
" This command generates 5 lists, each containing 10 random numbers ranging from 1 to 100." | |
] | |
-- | |
-- Lib | |
-- | |
takeM :: Int -> S.Set Int -> [IO Int] -> IO [Int] | |
takeM 0 set _ = pure $ S.toList set | |
takeM n set (randomX:xs) = | |
randomX >>= \x -> | |
if S.member x set | |
then takeM n set xs | |
else takeM (n - 1) (S.insert x set) xs | |
printList [] = putStr "\n" | |
printList (x:xs) = putStrLn (show x) >> printList xs |
Author
jeovazero
commented
Aug 28, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment