Skip to content

Instantly share code, notes, and snippets.

@jeovazero
Last active August 28, 2024 02:46
Show Gist options
  • Save jeovazero/bf59edd5a228dc47e90742801c9e064b to your computer and use it in GitHub Desktop.
Save jeovazero/bf59edd5a228dc47e90742801c9e064b to your computer and use it in GitHub Desktop.
{-# 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
@jeovazero
Copy link
Author

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment