import Control.Concurrent (forkIO)
import System.Environment (getArgs)
main= do
[a,b]<- getArgs
putStrLn $ "command line arguments: " ++ show [a,b]
When I compiled it, it was all right, but when I ran it,
it said "user error (Pattern match failure in do expression)", what is wrong here?
The problem is that you're pattern matching [a, b] on the return value of getArgs. If you run your program with anything other than 2 arguments, then the return value will not match the pattern [a, b]. So unless you run this program as
$ ./xie 1 2
command line arguments: ["1","2"]
It will throw an error. Instead, if you wrote your code
main = do
args <- getArgs
case args of
[a, b] -> putStrLn $ "command line arguments: " ++ show [a, b]
_ -> putStrLn "Invalid number of arguments"
then you would never fail on a pattern match.
The pattern [a,b] only matches a 2-element list, so if getArgs returns a list with a different number of elements, the match will fail.
When using do notation, when a match fails, the fail function is called, which in the case of IO causes a userError to be thrown.
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 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.
Can anyone tell me what is the problem with this Haskell program
import Control.Monad
import Data.Char
main = do
contents <- getContents
putStrLn $ contents
putStr $ "shortLinesOnly version is " ++ (shortLinesOnly contents)
putStr $ "printOnlyLessChars version is " ++ (printOnlyLessChars contents)
shortLinesOnly :: String -> String
shortLinesOnly input =
let allLines = lines input
shortLines = filter (\line -> length line < 10) allLines
result = unlines shortLines
in result
--------------------the other way of doing this is -----------------
printOnlyLessChars contents = unlines $ filter (\a -> length a < 10) $ lines $ contents
The program works fine, but it fails when I try to print the contents (line 5). Why is it having problems printing the string via putStrLn
The error message I get is
* Couldn't match expected type `(String -> IO ())
-> t0 -> IO String'
with actual type `IO String'
* The function `getContents' is applied to one argument,
but its type `IO String' has none
In the expression: getContents putStrLn
Thanks,
This is the line that you need to focus on:
In the expression: getContents putStrLn
This is haskell showing you how it views your code, but your code doesn't look like that. This is almost always an indentation error. Check that you don't have an extra space or a tab where it doesn't belong.
As a suggestion when reading haskell type error messages there are three places to look, and you should scan all of them before fixating on a single one:
The type signature information -- do your types really match?
The expression information -- does the expression the compiler sees match your expectations, or do you need to add $ or parens
Is there a typo or indentation problem.
I frequently feel my brain starting to overheat as I try to read through a really messy Couldn't match expected type so before I get too upset over trying to read that part of the error message I carefully check the In the expression: part to make sure that there is an easy to fix issue with how I entered the code.
I am trying to recreate the output of this Haskell code:
forM_ = flip mapM_
import Control.Monad.Cont
main = do
forM_ [1..3] $ \i -> do
print i
forM_ [7..9] $ \j -> do
print j
withBreak $ \break ->
forM_ [1..] $ \_ -> do
p "loop"
break ()
where
withBreak = (`runContT` return) . callCC
p = liftIO . putStrLn
The expected output is as follows:
$ runhaskell for.hs
1
2
3
7
8
9
loop
But I am getting the following error:
Test4.hs:2:1: parse error on input `import'
Any ideas about what is going wrong?
Test4.hs:2:1: parse error on input `import'
The error points to the second line of your file. Quoting the first two lines:
forM_ = flip mapM_
import Control.Monad.Cont
The problem is that an import declaration must be at the beginning of a module, before any definitions (the only things that can come before an import are language pragmas, such as those used to enable GHC extensions, and the module declaration). In your case, the first line of the file is a definition, and so the misplaced import declaration in the second line leads to a parse error. Since that first line wasn't actually part of the code snippet in the post you linked to, you can simply delete it.
Because I oversimplified in my other question before, I would like to give a more clear example here.
How can I handle situations where I have to check for certian conditions in a sequential way without nesting multiple cases? With "sequential way" I mean getting a value (e.g. from stdin), checking this value for a certain condition and depending on the outcome getting another value and so on.
Example:
sequen :: IO String
sequen = do
a <- getLine
case a of
"hi" -> do
putStrLn "hello!"
b <- getLine
case b of
"how are you?" -> do
putStrLn "fine, thanks"
return "nice conversation"
_ -> return "error 2"
_ -> return "error 1"
I know that there are better ways to write such a chat bot, it should just demonstrate the sequential nature of the problem. As you can see, with every nested case, the code also gets indented deeper.
Is there a way to better structure such code? I'm thinking of handling the "errors" on one place and describing the "success-path" without the error handling distributed all over it.
Of course. This is precisely what EitherT was made for. You can get it from Control.Monad.Trans.Either in the eitherT package.
import Control.Monad.Trans.Class
import Control.Monad.Trans.Either
main = do
e <- runEitherT $ do
a <- lift getLine
case a of
"hi" -> lift $ putStrLn "hello!"
_ -> left 1
b <- lift getLine
case b of
"how are you?" -> lift $ putStrLn "fine, thanks!"
_ -> left 2
return "nice conversation"
case e of
Left n -> putStrLn $ "Error - Code: " ++ show n
Right str -> putStrLn $ "Success - String: " ++ str
EitherT aborts the current code block whenever it encounters a left statement, and people typically use this to indicate error conditions.
The inner block's type is EitherT Int IO String. When you runEitherT it, you get IO (Either Int String). The Left type corresponds to the case where it failed with a left and the Right value means it successfully reached the end of the block.
I wrote a series of posts a while back going over my own learnings of the Either & EitherT types. You can read it here: http://watchchrislearn.com/blog/2013/12/01/working-entirely-in-eithert/
I use the errors package to get a bunch of nice helpers around using EitherT (left and right functions for instance to return lifted versions of Left and Right).
By extracting your potential failure conditions into their own helpers, you can make the mainline of your code read totally sequentially, with no case statements checking results.
From that post, you can see how the runEitherT section is a sequential chunk of work, it just happens to have the failure mechanics of EitherT. Obviously this code is fairly contrived to show how MaybeT plays inside of EitherT as well. In real code it'd just be the story you were wanting to tell, with a single Left/Right at the end.
import Control.Error
import Control.Monad.Trans
-- A type for my example functions to pass or fail on.
data Flag = Pass | Error
main :: IO ()
main = do
putStrLn "Starting to do work:"
result <- runEitherT $ do
lift $ putStrLn "Give me the first input please:"
initialText <- lift getLine
x <- eitherFailure Error initialText
lift $ putStrLn "Give me the second input please:"
secondText <- lift getLine
y <- eitherFailure Pass (secondText ++ x)
noteT ("Failed the Maybe: " ++ y) $ maybeFailure Pass y
case result of
Left val -> putStrLn $ "Work Result: Failed\n " ++ val
Right val -> putStrLn $ "Work Result: Passed\n " ++ val
putStrLn "Ok, finished. Have a nice day"
eitherFailure :: Monad m => Flag -> String -> EitherT String m String
eitherFailure Pass val = right $ "-> Passed " ++ val
eitherFailure Error val = left $ "-> Failed " ++ val
maybeFailure :: Monad m => Flag -> String -> MaybeT m String
maybeFailure Pass val = just $ "-> Passed maybe " ++ val
maybeFailure Error _ = nothing
Since you are necessarily in the IO monad, you are better off using the IO monad's error handling capabilities instead of stacking an error monad on top of IO. It avoids all of the heavy lifting:
import Control.Monad ( unless )
import Control.Exception ( catch )
import Prelude hiding ( catch )
import System.IO.Error ( ioeGetErrorString )
main' = do
a <- getLine
unless (a == "hi") $ fail "error 1"
putStrLn "hello!"
b <- getLine
unless (b == "how are you?") $ fail "error 2"
putStrLn "fine, thanks"
return "nice conversation"
main = catch main' $ return . ioeGetErrorString
In this case, your errors are simply Strings, which are thrown by IO's fail, as a userError. If you want to throw some other type, you will need to use throwIO instead of fail.
At some point the EitherT package was deprecated (though transformers-either offers a similar API). Fortunately there's an alternative to EitherT that doesn't even require installing a separate package.
The standard Haskell installation comes with the Control.Monad.Trans.Except module (from the transformers package, which is bundled with GHC), which behaves almost identically to EitherT. The resulting code is almost identical to the code in Gabriella Gonzalez's answer, but using runExceptT instead of runEitherT and throwE instead of left.
import Control.Monad.Trans.Class
import Control.Monad.Trans.Except
main = do
e <- runExceptT $ do
a <- lift getLine
case a of
"hi" -> lift $ putStrLn "hello!"
_ -> throwE 1
b <- lift getLine
case b of
"how are you?" -> lift $ putStrLn "fine, thanks!"
_ -> throwE 2
return "nice conversation"
case e of
Left n -> putStrLn $ "Error - Code: " ++ show n
Right str -> putStrLn $ "Success - String: " ++ str
(Note that the aforementioned transformers-either package is in fact a wrapper for ExceptT designed for providing compatibility with code that still uses EitherT.)
Warning: fellow Haskell newbie answering.
You can avoid this sort of staircasing with the Maybe monad. Good example at the start of this chapter
However, you'd want something similar with a monadic Either (presumably there is one) since you're returning error codes.
The basic idea being that once you've got a "Left 1" error you'll short-circuit any future steps (because of lazy evaluation).