Parsing command line arguments in Haskell - haskell

I am currently working on a project that requires parsing command line arguments. So far I have been following this tutorial, which has been incredibly helpful, but I can't figure out how to return a variable (--author=example) in the arguments. I also can't figure out why parse [] = getContents causes an error (I had to uncomment it).
Here is my code:
module Main where
import qualified System.Environment as SE
import qualified System.Exit as E
import qualified Lib as Lib
main = do
args <- SE.getArgs
rem <- parse args
Lib.someFunc
putStrLn rem
putStrLn "Hello"
tac = unlines . reverse . lines
parse ["--help"] = usage >> exit
parse ["--version"] = version >> exit
parse ["--author=xyz"] = return "xyz"
-- parse ["--author=?"] = ?
{-
this is the code I am trying to figure out... how do I get parse the passed in variable name?
-}
-- parse [] = getContents
{-
the above line generates this error when I run 'main' in GHCi:
*Main> <stdin>: hIsEOF: illegal operation (handle is semi-closed)
Process intero exited abnormally with code 1
-}
parse fs = concat `fmap` mapM readFile fs
usage = putStrLn "Usage: gc2"
version = putStrLn "gc2 -- git-cal in Haskell2010 - 0.1"
exit = E.exitWith E.ExitSuccess
die = E.exitWith (E.ExitFailure 1)

To follow up on #ThomasM.DuBuisson comment optparse-applicative is a great package for cli and arguments parsing. There is also another package optparse-simple that is built on top of the previous one and has a few helpers that simplify things a bit.
Just so you can get started with optparse-applicative here is an implementation of your example:
data Options = Options
{ author :: String
}
main :: IO ()
main = do
let ver = "gc2 -- git-cal in Haskell2010 - 0.1"
args <-
execParser $
info
(Options <$>
strOption (long "author" <>
short 'a' <>
help "Name of the author.") <*
infoOption ver (long "version" <>
short 'v' <>
help "Display version and exit.") <*
abortOption ShowHelpText (long "help" <>
short 'h' <>
help "Display this message."))
(progDesc "Very powerful tool." <> fullDesc)
putStrLn $ author args
And usage example from GHCi:
λ> :main
Missing: (-a|--author ARG)
Usage: <interactive> (-a|--author ARG) [-v|--version] [-h|--help]
Very powerful tool.
*** Exception: ExitFailure 1
λ> :main --version
gc2 -- git-cal in Haskell2010 - 0.1
*** Exception: ExitSuccess
λ> :main --help
Usage: <interactive> (-a|--author ARG) [-v|--version] [-h|--help]
Very powerful tool.
Available options:
-a,--author ARG Name of the author.
-v,--version Display version and exit.
-h,--help Display this message.
*** Exception: ExitSuccess
λ> :main --author Me
Me

Related

Haskell eval (from plugins package) runtime error

I have this code
module Main where
import System.Eval.Haskell
test = "a"
main :: IO ()
main = do
putStrLn "Hello, Haskell!"
i <- eval "1 + 6 :: Int" [] :: IO (Maybe Int)
when (isJust i) $ putStrLn (show (fromJust i))
putStrLn test
I run "cabal run -v"
Result:
this build was affected by the following (project) config files:
Up to date
creating /home/n0lim/HaskellProjects/TrophicModels/dist-newstyle/build
creating /home/n0lim/HaskellProjects/TrophicModels/dist-newstyle/tmp
Selecting TrophicModels-0.1.0-inplace-TrophicModels to supply
TrophicModels
/home/n0lim/HaskellProjects/TrophicModels/dist-newstyle/build/x86_64-linux/ghc-8.10.5/TrophicModels-0.1.0/x/TrophicModels/build/TrophicModels/TrophicModels
Hello, Haskell!
< command line >: cannot satisfy -package plugins
(use -v for more information)
a
Which -v was implied and what is wrong with eval?

Why am i getting a parse error and how can i solve this error in haskell?

I'm new to Haskell and while reading real-world Haskell I came across a problem:
Q) Using the command framework from the earlier section “A Simple Command-Line Framework” on page 71, write a program that prints the first word of each line of its input.
The command framework is:
-- file: ch04/InteractWith.hs
-- Save this in a source file, e.g., Interact.hs
import System.Environment (getArgs)
interactWith function inputFile outputFile = do
input <- readFile inputFile
writeFile outputFile (function input)
main = mainWith myFunction
where mainWith function = do
args <- getArgs
case args of
[input,output] -> interactWith function input output
_ -> putStrLn "error: exactly two arguments needed"
-- replace "id" with the name of our function below
myFunction = id
My solution to the problem is:
-- file: ch04/InteractWith.hs
-- Save this in a source file, e.g., Interact.hs
import System.Environment (getArgs)
interactWith function inputFile outputFile = do
input <- readFile inputFile
writeFile outputFile (function input)
main = mainWith myFunction
where mainWith function = do
args <- getArgs
case args of
[input,output] -> interactWith function input output
_ -> putStrLn "error: exactly two arguments needed"
-- replace "id" with the name of our function below
myFunction = concat (map (++"\n") (map head (map words (lines input))))
As per instructions, whenever I try to compile this program using ghc --make filename I get a parse error i.e.
error: parse error on input ‘args’
|
36 | args <- getArgs
| ^^^^
Your indentation is off.
Haskell is sensitive to whitespace. In particular, among other things, the "inside" of a "block" must generally be indented farther to the right than the beginning of that block. In your case this means that the inside of do must be indented to the right of mainWith on the preceding line.
Try this:
main = mainWith myFunction
where mainWith function = do
args <- getArgs
case args of
[input,output] -> interactWith function input output
_ -> putStrLn "error: exactly two arguments needed"

Haskell - putStrLn multiple calls not printing

Hi so I have this main method which runs a parser,
main = do
args <- getArgs
let filename = head args
contents <- readFile filename
let c = parse parseProgram contents
putStrLn "------------------------------------------------"
putStrLn "THE PROGRAM WE HAVE PARSED"
putStrLn "------------------------------------------------"
putStrLn (show ((fst.head) c))
return ()
when I run this program the first three calls to putStrLn are not printed to the terminal, it only shows the parsed program.
any help will be appreciated, how do I get all the calls to print?
This doesn't appear possible. I created a more minimal example following as closely as possible to your code. I used Parsec because I am not sure what parsing library you are using.
Contents of parsec-trivial.hs:
#!/usr/bin/env stack
{- stack
--resolver lts-6.15
--install-ghc
runghc
--package parsec
-}
import System.Environment
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Char
ws = many space
nat :: Parser Integer
nat = read <$> many digit
parseProgram = ws *> nat <* ws <* eof
main = do
args <- getArgs
let filename = head args
contents <- readFile filename
let c = parse parseProgram filename contents
putStrLn "------------------------------------------------"
putStrLn "THE PROGRAM WE HAVE PARSED"
putStrLn "------------------------------------------------"
putStrLn $ show c
Contents of foo.b:
42
Executing this program goes like this:
$ ./parsec-trivial.hs foo.b
------------------------------------------------
THE PROGRAM WE HAVE PARSED
------------------------------------------------
Right 42

hidden arguments with cmdargs

I would like to use cmdargs to pass arguments to my Haskell program. For some reasons, I would like some options to be hidden (not shown but usable) in the cmdargs help message.
Is there a way to do to that?
I'm using cmdargs 0.10.9.
The idea here is to intercept the --help processing and edit the
help text to remove any references to hidden options before displaying it.
Options we wish to hide can be marked with special help text (e.g. &= help "HIDDEN OPTION")
and those lines can be removed from the help output.
Consider this simple main program:
main = cmdArgs sampleArgs >>= print
The path taken when --help is present is as follows:
cmdArgs = cmdArgsRun . cmdArgsMode
cmdArgs m = cmdArgsApply =<< processArgs m
cmdArgsApply :: CmdArgs a -> IO a
cmdArgsApply CmdArgs{..}
| Just x <- cmdArgsHelp = do putStr x; exitSuccess
| Just x <- cmdArgsVersion = ...
| otherwise = ...
To intercept help processing we can write our main like this:
main = do
b <- processArgs (cmdArgsMode sampleArgs)
a <- myApply b
print a
where myApply is a version of cmdArgsApply which emits the edited
version of the help text.
Here is working example. The options -s and --secret will not be shown in the help text. Try it with these arguments:
prog
prog --help
prog --version
prog -s1234
Program:
{-# LANGUAGE DeriveDataTypeable, RecordWildCards #-}
import Data.List (isInfixOf)
import System.Console.CmdArgs
import System.Console.CmdArgs.Explicit (processArgs)
import System.Exit (exitSuccess)
data MyArgs = MyArgs { file :: String, dest :: String, secret :: String }
deriving (Show, Data)
sample = MyArgs { file = "input.txt" &= help "the input file" &= opt "input"
, dest = "output.txt" &= help "the output file"
, secret = "3l33t" &= help "HIDDEN OPTION" &= opt "someflag"
}
main = do
b <- processArgs (cmdArgsMode sample)
a <- myApply b
putStrLn $ "running program with " ++ show a
myApply :: CmdArgs a -> IO a
myApply b#CmdArgs{..}
| Just x <- cmdArgsHelp = do putStr (fixupHelp x); exitSuccess
| otherwise = cmdArgsApply b
fixupHelp = unlines
. filter (not . ("HIDDEN OPTION" `isInfixOf`))
. lines

parsec error in haskelwiki tutorial

I was following the code in http://www.haskell.org/haskellwiki/Hitchhikers_guide_to_Haskell, and the code (in chapter 2) gives an error. There is no author name/email mentioned with the tutorial, so I am coming here for advise. The code is below, and the error occurs on the "eof" word.
module Main where
import Text.ParserCombinators.Parsec
parseInput =
do dirs <- many dirAndSize
eof
return dirs
data Dir = Dir Int String deriving Show
dirAndSize =
do size <- many1 digit
spaces
dir_name <- anyChar `manyTill` newline
return (Dir (read size) dir_name)
main = do
input <- getContents
putStrLn ("Debug: got inputs: " ++ input)
That tutorial was written a long time ago, when parsec was simple. Nowadays, since parsec-3, the library can wrap monads, so you now have to specify (or otherwise disambiguate) the type to use at some points. This is one of them, giving eof e.g. the expression type signature eof :: Parser () makes it compile.

Resources