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
Related
I am trying to understand getArgs in Haskell. Here is what I have:
import System.Environment
myFunFunction = do
args <- getArgs
return $ head args
What I am getting when I run the function is
*Main> myFunFunction
*** Exception: Prelude.head: empty list
Does this not work the same way as getLine? Why does it not ask for a command line argument?
The type of getArgs is IO [String]. When you bind it with <-, as in the OP, the bound symbol (args) gets the type [String], i.e. a list of strings.
The head function returns the first element in a list; it has the type [a] -> a. It's (in)famous for being unsafe, in the sense that if you apply it to an empty list, it'll crash:
Prelude System.Environment> head []
*** Exception: Prelude.head: empty list
That's what's happening here. getArgs gives you the arguments you supplied at the command line when you ran the program. If you don't supply any arguments at the command line, then the returned list will be empty.
The getArgs function isn't interactive. It'll just return the arguments supplied from the command line, if any were supplied.
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"]
I'm trying to execute a main method within one of my classes in haskell. When I run the command runhaskell mod12PA.hs I get an error and I can't figure out why.
Here's the code:
-- The main program: read points from stdin, write an SVG file to stdout.
main :: IO ()
main = do
putStrLn "Enter points: "
points <- getLine
putStrLn ("Points: " ++ points)
The error:
<interactive>:41:1: error:
Variable not in scope: runhaskell :: t0 -> b0 -> c
<interactive>:41:12: error: Variable not in scope: mod12PA
<interactive>:41:20: error: Variable not in scope: hs :: a -> b0
Was able to figure out that I needed to be compiling the file outside of ghci and then running the executable. I was trying to execute the file from within ghci which was not working.
Ran ghc --make mod12PA.hs
Then mod12PA.exe
While you do need to run the command outside of GHCi, runhaskell mod12PA.hs should work. (runhaskell serves a different purpose than ghc --make: it runs the code without compiling it.)
I have problem with reading from file. Whenever I need to read from a file, I do something like this:
main = do x <- readFile "/tmp/foo.txt"
putStr x
But now I would like the path to be an argument, so I tried the following
main s = do x <- readFile s
putStr x
It doesn't work. I see the following error:
Couldn't match expected type `IO t0'
with actual type `FilePath -> IO ()'
In the expression: main
When checking the type of the function `main'
My homework is to write a program and the program has to contain a main function (because it will be compiled) and argument of call must contain the name of the file. I'm not sure I understand this and I don't know how to proceed. I will grateful for some help.
The Haskell report specifies that the main function always has type IO t, (for some type t which will be ignored) and hence never takes normal function arguments, so this is not the right approach.
You are looking for the function getArgs (for which you have to import the module System.Environment. It returns the arguments passed to your program as a list of Strings.
So your code would look like:
import System.Environment
main = do
args <- getArgs
case args of
[file] -> do
x <- readFile file
putStr x
_ -> putStrLn "Wrong number of arguments"
In Haskell, the arguments are NOT given to the main function because of the way Haskell binds its start up and to remain consistent. You need to use System.Environment.getArgs.
In particular, because Haskell is a pure functional language, main is a monadic action that organizes the side-effect-ful computations performed by the software – the result computed by main is discarded, because in functional languages you are detached from the environment w.r.t. computation and only interact with it as a side-effect.
Example
import System.Environment
main = do x <- getArgs; print x
This will print out whatever you type on the command line.
The Haskell wiki has an excellent tutorial on the topic.
I'm using ghci 6.10.4 at the dos command line in XP, and also in emacs using haskell-mode-2.4
When running programs that operate on stdin, is there a way I can redirect a file to be stdin? For example if I have a function called main that reads from stdin, I can't do:
*Main> main < words.txt
Is there another way?
Also I would like to be able to type stdin into the ghci window, which seems to work, but what is the EOF key? I thought it was Ctrl-D but that doesn't work.
This will be easier if you rework your main to open the file itself.
import System.Environment
import System.IO
main :: IO ()
main = do
args <- getArgs
case args of
[] -> doStuff stdin
file:_ ->
withFile file ReadMode doStuff
doStuff :: Handle -> IO ()
doStuff = …
*Main> System.Environment.withArgs ["main.txt"] main
Don't give a EOF on stdin while within GHCi. If you do, all further attempts to read from stdin will fail:
Prelude> getLine
*** Exception: <stdin>: hGetLine: illegal operation (handle is closed)
Prelude> getContents
*** Exception: <stdin>: hGetContents: illegal operation (handle is closed)
You CAN type :main in GHCi to invoke command line parameters. I'm afraid you'll probably just want to use that.