Mandatory arguments with cmdargs - haskell

Using cmdargs, is there a convenient way to print an error message and exit if a mandatory argument is missing? E.g. right now I have something like:
foo = Foo{script = def &= args &= typ "SCRIPT"}
main = do
scriptName <- script <$> cmdArgs foo
-- ...
If I run this program and don't pass the SCRIPT argument, scriptName is simply an empty string. Do I really have to manually check for and handle that using something like Control.Monad.Except?

Related

Haskell: Why does this function keep asking for user input and not terminating

I'm learning some Haskell and I came across this small program
reverseLines :: String -> String
reverseLines input =
unlines (map reverse (lines input))
main :: IO ()
main = interact reverseLines
This program will keep asking the user for more input and reverse the input and print it on the screen.
Most of this is straight forward but one thing I can't wrap my head around is why does this function keeps running and ask the user for more input whereas if I just replace the reverseLines function with a function the simply returns some string it will not happen.
This program will stop after one execution:
foo input = "Stops"
main :: IO ()
main = interact foo
Why?
If you look at the source of interact you see this:
interact f = do s <- getContents
putStr (f s)
see the getContents? This is where the magic starts - it will read everything till EOF
Now in Haskell this is lazy-IO which can be bad but here is almost magical - see the string is read lazily and passed to your reverseLines - this one of course will only generate output as soon as it saw \n characters (the lines) and so it seems your program is some kind of REPL.
In the second one you don't consume any of the lazy-string at all so it stops ASAP
As I wrote in the comments you can play with this by either passing content into the program using a file (or echo) and pipes on the terminal:
echo "Hello World\nBye Bye" | runhaskell LazyIO.hs
or using CTRL-D to pass in the EOF yourself.
To get a feeling for it I would play with the functions more - what happens if you use something that needs to see the complete input first (try reverse without the maps)? What happens with words instead of lines, ...?
Have fun!

Reading line by line in Haskell

I'm trying to read from standard input line by line, and process each line with the function of the type foo :: String -> Int. Is there any way to do that provided that we don't know the number of lines we want to read OR given that the number of lines is provided on the first line?
What I've tried
A lot of things that give meaningless errors, such as "parser error".
For example
main = do {
getLine <- getContents;
let result = show (foo getLine);
putStrLn (foo result);
}
Edit
Strange, but this does not print the length of a
main = do {
a <- getContents;
putStrLn (show (length a));
}
but, this does print 5.
main = do {
a <- getContents;
putStrLn (show 5);
}
The main example of doing that will look as this:
main = do
line <- getLine
yourfunction line
main
this will take lines forever and process them with your function, in case you want it to stop sometime, just check for a command for example:
main = do
line <- getLine
let res = yourfunction line
if res == "Exit" then IO () else main
You may use the function lines to convert the String into [String]. Afterwards map your foo over this list of lines.
Regarding the edit: Your program printing the length works for me. Try either inputting a file or - if entering input interactively - terminating it correctly (via Ctrl-d).
Sidenote: curly brackets and semicolons are rarely seen usually. But this is just style.

Where are the magic rules for GHC assert?

http://hackage.haskell.org/package/base-4.6.0.1/docs/src/GHC-Base.html#assert seems to define assert to be a no-op. Where's the logic that turns this into something else when assertions are enabled?
The comment above that function gives a hint:
-- Assertion function. This simply ignores its boolean argument.
-- The compiler may rewrite it to #('assertError' line)#.
So, just use github code search and search for assertError: search results
This turns up the file RnExpr.lhs. Searching for assert in this file, you'll find the following code:
finishHsVar :: Name -> RnM (HsExpr Name, FreeVars)
-- Separated from rnExpr because it's also used
-- when renaming infix expressions
-- See Note [Adding the implicit parameter to 'assert']
finishHsVar name
= do { this_mod <- getModule
; when (nameIsLocalOrFrom this_mod name) $
checkThLocalName name
; ignore_asserts <- goptM Opt_IgnoreAsserts
; if ignore_asserts || not (name `hasKey` assertIdKey)
then return (HsVar name, unitFV name)
else do { e <- mkAssertErrorExpr
; return (e, unitFV name) } }
That's where it replaces assert by assertError, but only if assertions are enabled.
assertError is defined in GHC.IO.Exception

Doing a readLine inside an if

I'm writing a small command-line utility in Haskell which should accept a command with an optional command-line argument - but if the argument is not present, the user should be prompted to enter it*. For example:
$ my_prog add item_name
Adding... done
$ my_prog add
Enter item name: item_name
Adding... done
My initial attempt looked something like this:
add args = do
let id = if length args > 0
then head args
else input where
input <- readLine
-- Do stuff with id
putStrLn id
Which fails to parse at the <-.
*I have since decided that this is a silly idea, but I thought I'd ask the question anyway.
You are attempting to use the do-notation inside the if, this will not work (and besides, won't typecheck since the whole if is outside the IO monad).
add args = do
id <- if length args > 0
then return $ head args
else readLine
putStrLn id

Haskell: Need Enlightenment with Calculator program

I have an assignment which is to create a calculator program in Haskell. For example, users will be able to use the calculator by command lines like:
>var cola =5; //define a random variable
>cola*2+1;
(print 11)
>var pepsi = 10
>coca > pepsi;
(print false)
>def coke(x,y) = x+y; //define a random function
>coke(cola,pepsi);
(print 15)
//and actually it's more complicated than above
I have no clue how to program this in Haskell. All I can think of right now is to read the command line as a String, parse it into an array of tokens. Maybe go through the array, detect keywords such "var", "def" then call functions var, def which store variables/functions in a List or something like that. But then how do I store data so that I can use them later in my computation?
Also am I on the right track because I am actually very confused what to do next? :(
*In addition, I am not allowed to use Parsec!*
It looks like you have two distinct kinds of input: declarations (creating new variables and functions) and expressions (calculating things).
You should first define some data structures so you can work out what sort of things you are going to be dealing with. Something like:
data Command = Define Definition | Calculate Expression | Quit
type Name = String
data Definition = DefVar Name Expression | DefFunc Name [Name] Expression
-- ^ alternatively, implement variables as zero-argument functions
-- and merge these cases
data Expression = Var Name | Add Expression Expression | -- ... other stuff
type Environment = [Definition]
To start off with, just parse (tokenise and then parse the tokens, perhaps) the stuff into a Command, and then decide what to do with it.
Expressions are comparatively easy. You assume you already have all the definitions you need (an Environment) and then just look up any variables or do additions or whatever.
Definitions are a bit trickier. Once you've decided what new definition to make, you need to add it to the environment. How exactly you do this depends on how exactly you iterate through the lines, but you'll need to pass the new environment back from the interpreter to the thing which fetches the next line and runs the interpreter on it. Something like:
main :: IO ()
main = mainLoop emptyEnv
where
emptyEnv = []
mainLoop :: Environment -> IO ()
mainLoop env = do
str <- getLine
case parseCommnad str of
Nothing -> do
putStrLn "parse failed!"
mainLoop env
Just Quit -> do
return ()
Just (Define d) -> do
mainLoop (d : env)
Just (Calculate e) -> do
putStrLn (calc env e)
mainLoop env
-- the real meat:
parseCommand :: String -> Maybe Command
calc :: Environment -> Expression -> String -- or Integer or some other appropriate type
calc will need to look stuff up in the environment you create as you go along, so you'll probably also need a function for finding which Definition corresponds to a given Name (or complaining that there isn't one).
Some other decisions you should make:
What do I do when someone tries to redefine a variable?
What if I used one of those variables in the definition of a function? Do I evaluate a function definition when it is created or when it is used?
These questions may affect the design of the above program, but I'll leave it up to you to work out how.
First, you can learn a lot from this tutorial for haskell programming
You need to write your function in another doc with .hs
And you can load the file from you compiler and use all the function you create
For example
plus :: Int -> Int -- that mean the function just work with a number of type int and return Int
plus x y = x + y -- they receive x and y and do the operation

Resources