I am trying to understand getArgs but I am getting a weird behavior that I am not understanding. Here is my program:
getMyArgs :: IO [String]
getMyArgs =do
x <- getArgs
return x
I run this and get:
*Main> hello <- getMyArgs
*Main>
Why doesn't it return my argument passed? I tried to put in a " show() " but that turns it into a String instead of a [String]
getMyArgs :: IO [String]
getMyArgs =do
x <- getArgs
return x
The do notation desugars to:
getMyArgs :: IO [String]
getMyArgs = getArgs >>= \x -> return x
Using the right identity we can rewrite this to:
getMyArgs :: IO [String]
getMyArgs = getArgs
So you've just defined a new name for getArgs. Now why does getArgs not show your program arguments? Well it appears you didn't provide any program arguments. In the interpreter it can be tricky to provide arguments - one way is to :set them:
Prelude> :set args hello world
Prelude> import System.Environment
Prelude System.Environment> getArgs
["hello","world"]
EDIT: Oh you might be looking to print the value you bound. Consider:
Prelude System.Environment> hello <- getArgs
Prelude System.Environment> print hello
["hello","world"]
Thanks to #4castle for this observation.
Assume your Haskell program is compiled to an executable foo. When you call your program, you want to pass some runtime arguments to your program eg foo param1 param2 . Depending on the values of param1 and param2 you will take different actions in your program.
Now with the getArgs function you get access to these parameters in your Haskell program.
In GHCi this argument passing can be simulated. Either with the :set args paarm1 param2 command as shown in the answer of Thomas M. DuBuisson
or you call your main program in GHCI with :main param1 param2 .
In both scenarios getEnv will return IO ["param1", "param2"]
Related
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"
I'm trying to get from my console a string or just a char and store into a variable.
I tried to use:
> let x = getChar
> x
> c -- for getting a char.
But nothing is stored (same for getLine) how can I do?
The type of getChar is IO Char. It is not a function that returns a Char; it is an IO action that, when executed, returns a Char. (While subtle, this distinction is crucial to understanding how Haskell performs IO with pure functions.)
The line
let x = getChar
just binds the name x to the same IO action (which you can see by subsequently typing :t x in GHCi). Typing x then executes that action; GHCI waits for you to type a character, then it immediately returns that character.
To use getChar in a program, you need to use it within an IO monad, with something like
main = do ch <- getChar
print ch
or
main = getChar >>= print
Here is a sample
main = do
x <- getLine
putStrLn $ "Here is the string you typed in: " ++ x
Reading from console, maybe is not very useful. However you should use <- construct.
For example (without " is good too) :
>myString <- getLine
>"Hello world"
or
>myChar <- getChar
>c
For more I suggest to read here
You need to bind it to a variable using <-, the result of an action is being bound:
*Main> variable <- getLine
hello
*Main> putStrLn variable
hello
*Main> anotherChar <- getChar
a*Main>
*Main> putChar anotherChar
a*Main>
Function getLine has type IO String and getChar has type IO Char.
I am attempting to run my program using the command line. I am trying to return my command line arguments:
import System.Environment
import Data.List
main :: IO()
main = do
args <- getArgs
progName <- getProgName
putStrLn "The arguments are:"
mapM putStrLn args
putStrLn "The program name is:"
putStrLn progName
I am executing the code by calling the main function with my arguments:
main argument arguments "more arguements"
However, I am getting a complier error:
<interactive>:33:6: Not in scope: ‘argument’
<interactive>:33:15: Not in scope: ‘arguments’
Is there an issue with how I am calling my function with my arguments?
You have to use :main if you want to simulate command line arguments. main alone only executes your IO () action, but doesn't actually build the arguments. For all what GHCi knows, main doesn't necessarily need to be IO (), it could be Int -> Int -> IO ().
However, if you use :main, GHC will use main in the same way it would get invoked during an runhaskell call, e.g. with interpreting the following parameters as command line arguments.
Alternatively, you can use withArgs from System.Environment:
ghci> withArgs ["argument", "arguments", "more arguments"] main
I am trying to get an int value from the command line and pass it to the disp function.
import System(getArgs)
main = do
args <- getArgs
disp $ read $ head args :: Int
disp n = take n $ repeat 'S'
The error given by ghc is
Couldn't match expected type `Int' with actual type `[Char]'
In the expression: disp $ read $ head args :: Int
In the expression:
do { args <- getArgs;
disp $ read $ head args :: Int }
In an equation for `main':
main
= do { args <- getArgs;
disp $ read $ head args :: Int }
Thanks.
The problem is with precendence: Type signatures always try to apply to the whole expression (only scoped using parenthesis). So your disp $ read $ head args :: Int parses as (disp $ read $ head args) :: Int, which is obviously not correct. You can either use parenthesis like so:
disp (read $ head args :: Int)
or omit the type signature, as GHC can infer it in this case:
disp $ read $ head args
This code still won't work as-is, because you're in the IO monad so you need to produce IO actions. You can do this by printing the result, for example:
putStrLn $ disp $ read $ head args
You can encapsulate pulling an integer command-line argument like so:
getIntArg :: IO Int
getIntArg = fmap (read . head) getArgs
Which works because Monads are Functors. Or you can do the same thing with liftM.
That way your main function just becomes:
main = do
n <- getIntArg
disp n
Provided you add some type of print function to disp as discussed in the other answers.
Just remove that explicit type you added there, and it'll work. Have faith in type inference. :) Add print $ ... there, or something similar, to correct the new error.
What happens is, the type of take is known, so the type of the argument that disp expects is known too. It is Int. So the appropriate read will be applied.
Do less, get done more.
I'm writing a little shell script in Haskell which can take an optional argument. However, if the argument is not present, I'd like to get a line from stdin in which to ask for a value.
What would be the idiomatic way to do this in Haskell?
#!/usr/bin/env runhaskell
import Control.Applicative ((<$>))
import Data.Char (toLower)
import IO (hFlush, stdout)
import System.Environment (getArgs)
main :: IO ()
main = do args <- getArgs
-- here should be some sort of branching logic that reads
-- the prompt unless `length args == 1`
name <- lowerCase <$> readPrompt "Gimme arg: "
putStrLn name
lowerCase = map toLower
flushString :: String -> IO ()
flushString s = putStr s >> hFlush stdout
readPrompt :: String -> IO String
readPrompt prompt = flushString prompt >> getLine
Oh, and if there's a way to do it with something from Control.Applicative or Control.Arrow I'd like to know. I've become quite keen on these two modules.
Thanks!
main :: IO ()
main = do args <- getArgs
name <- lowerCase <$> case args of
[arg] -> return arg
_ -> readPrompt "Gimme arg: "
putStrLn name
This doesn't fit your specific use case, but the question title made me think immediately of when from Control.Monad. Straight from the docs:
when :: Monad m => Bool -> m () -> m ()
Conditional execution of monadic expressions.
Example:
main = do args <- getArgs
-- arg <- something like what FUZxxl did..
when (length args == 1) (putStrLn $ "Using command line arg: " ++ arg)
-- continue using arg...
You can also use when's cousin unless in similar fashion.