I am trying following code with try-catch block:
import System.Environment
import System.IO
import System.IO.Error
import Control.Exception
isBinary :: String -> Bool
isBinary ss = do
print "In isBinary fn" -- works if this line is removed.
let ans = any (\c -> ord c > 127) ss
ans
toTry :: String -> IO ()
toTry firline = do
print "In toTry fn."
let answer = isBinary firline
if not answer then do
print "Sent line not binary: "
else
print "Sent line binary"
handler :: IOError -> IO ()
handler e = putStrLn "Whoops, had some trouble!"
ss = "this is a test"
main = do
toTry ss `catch` handler
However, I am getting following error:
$ runghc trycatch3.hs
trycatch3.hs:9:9: error:
• Couldn't match expected type ‘Bool’ with actual type ‘IO Bool’
• In a stmt of a 'do' block: print "in isBinary fn"
In the expression:
do { print "in isBinary fn";
let ans = any (\ c -> ...) ss;
return ans }
In an equation for ‘isBinary’:
isBinary ss
= do { print "in isBinary fn";
let ans = ...;
return ans }
trycatch3.hs:10:30: error:
• Variable not in scope: ord :: Char -> Integer
• Perhaps you meant one of these:
‘or’ (imported from Prelude), ‘odd’ (imported from Prelude)
The error goes away and program works well if the print statement is removed from isBinary function.
Why can't I put print statement in this function?
The answer is, "because types". Specifically:
isBinary :: String -> Bool
isBinary ss = do
....
Since it's a do block, the return type of isBinary must match a monadic type Monad m => m t for some m and some t. Here, since print "" :: IO (), m is IO, so it should've been
isBinary :: String -> IO Bool
isBinary ss = do
and now
print "In isBinary fn" -- works
let ans = any (\c -> ord c > 127) ss -- also works
ans -- doesn't work
ans doesn't work because of types, again. Its type is Bool, but it must be IO Bool -- first, because this do block belongs to IO monad, on account of print; and second, because of the return type of the function as a whole.
Instead, use
return ans
and now it'll work, because return injects a value into the monadic context, and being the last do block value it becomes the value produced by the do block overall (if return val appears in the middle it just passes the val to the next step in the combined computation).
The function toTry will have to be augmented to use the new definition:
toTry :: String -> IO ()
toTry firline = do
print "In toTry fn."
-- let answer = isBinary firline -- incorrect, now!
answer <- isBinary firline -- isBinary ... :: IO Bool
if not answer then do -- answer :: Bool
print "Sent line not binary: "
else
print "Sent line binary"
m a on the right of <-, a on the left.
See this for a general description of do notation.
You might be confused by the same print line working in toTry, but not in isBinary. The difference stems from the declaration:
isBinary :: String -> Bool
This means that isBinary is a pure function (i.e. no side effects), taking a string and returning a boolean. In fact, you could simplify it to
isBinary ss = any (\c -> ord c > 127) ss
or even use the point-free style
isBinary = any (\c -> ord c > 127)
However, toTry is
toTry :: String -> IO ()
I.e. it takes a string and returns the IO monad which is impure (can have side effects, such as printing text to the console).
Haskell is a language that encourages using pure functions, and enforces it using the type system, by forcing the programmer to explicitly mark impure code.
Further reading:
What does "pure" mean in "pure functional language"?
Looking at your code, it seems your use of print in isBinary is not an integral part of what you want the function to do, but merely a debug print statement that will be removed later on. In that case, you do not want to change the type of isBinary to String -> IO Bool (for more on that, see Will Ness' answer), as you don't actually need IO except for debugging. Rather, the core libraries offer the Debug.Trace module, which caters to this kind of situation. With it, we can add your debug print statement like this:
isBinary :: String -> Bool
isBinary ss = trace "In isBinary fn" $ any (\c -> ord c > 127) ss
Then, once you are done debugging, you can remove the use of trace -- and it bears repeating you really should do that later on. Quoting the Debug.Trace documentation:
Functions for tracing and monitoring execution.
These can be useful for investigating bugs or performance problems. They should not be used in production code.
Related
I have a function "management" that checks parameters and return a Maybe (String):
If there are not parameter -> return Nothing
If my parameter is equal to "-h" -> Return a string help
My problem arrived when I get a file and check if this file exists.
Couldn't match expected type ‘Maybe String’
with actual type ‘IO (Either e0 a2)’
managagment :: [String] -> Maybe (String)
managagment [] = Nothing
managagment ["-h"] = Just (help)
managagment [file] = try $ readFile file >>= \result -> case result of
Left e -> Nothing
Right content -> Just (content)
There are several problems
Function application ($) is lower precedence than bind (>>=)
You said:
try $ readFile file >>= \res...
Which means
try ( readFile file >>= \res... )
But you wanted:
try ( readFile file ) >>= \res...
IO (Maybe a) and Maybe a are distinct
You have a function using IO (via readFile and try) but many of the cases do not return an IO result (Nothing and Just content).
Solution: Return via return Nothing or pure Nothing to lift a value into the IO monad.
The exception type was ambiguous
The try function can catch any exception type, just look at the signature:
try :: Exception e => IO a -> IO (Either e a)
When you totally ignore the exception you leave the type checker with no information to decide what e should be. In these situations an explicit type signature is useful, such as:
Left (e::SomeException) -> pure Nothing
managagment is partial
managagment ["a","b"] is undefined as is any input list of length over one. Consider a final equational definition of:
managagment _ = managagment ["-h"]
Or more directly:
managagment _ = pure $ Just help
Style and other notes
managagment should probably management
Just (foo) is generally Just foo
help is not a function that returns a String. It is a value of type String.
The example was not complete, missing imports and help.
Fixed Code
Consider instead:
#!/usr/bin/env cabal
{- cabal:
build-depends: base
-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE LambdaCase #-}
import Control.Exception (try, SomeException)
main :: IO ()
main = print =<< management []
help :: String
help = "so helpful"
management :: [String] -> IO (Maybe String)
management [] = pure Nothing
management ["-h"] = pure $ Just help
management [file] =
try (readFile file) >>=
\case
Left (e::SomeException) -> pure Nothing
Right content -> pure $ Just content
management _ = pure $ Just help
And test as such:
% chmod +x x.hs
% ./x.hs
I am trying to make a guess the number game.
`
main :: IO()
checkGuess :: (Integral a) => a -> Bool
checkGuess b = if b == 9 then return True
main = do
print "Guess the number?"
guess <- getLine
checkGuess guess
but I get parse error on input '::' at the function checkGuess
There are several things that are wrong here:
you do not define the function directly after you wrote the signature of the function. You thus should first write the signature, and then write its binding, strictly speaking this is not an error as #chi says, but it is nevertheless strongly recommended;
In Haskell indentation matters: entering and leaving an indentation level says that you start or end a code block, for example for a where clause;
your checkGuess is supposed to return a Bool, but with return True, you make it a Monad m => m Bool;
in Haskell an if ... then ... else ... without an else does not exist. That is logical since a function should always return something;
getLine has as type IO String, so guess has type String, not Int, Integer, so you can not use guess directly to compare with a number; and
as #Krantz pointed out, the print here should probably be a putStrLn, since otherwise we print a string literal, not the string content.
In general it looks like you are writing an imperative program in a (pure) function language. A quick fix is the following:
checkGuess :: (Eq a, Num a) => a -> Bool
checkGuess = (9 ==)
main :: IO()
main = do
putStrLn "Guess the number?"
guess <- readLn :: IO Int
print (checkGuess guess)
I'm trying to write code that will prompt the user to enter a Float and will continue to do so until a valid float is entered.
I've tried the following approach:
getFloat :: Float
getFloat = do
input <- getLine
case (readMaybe input :: Maybe Float) of Just f -> f
Nothing -> do getFloat
But I'm getting the following error:
Main.hs:41:5:
Couldn't match type `IO b0' with `Float'
Expected type: IO String -> (String -> IO b0) -> Float
Actual type: IO String -> (String -> IO b0) -> IO b0
In a stmt of a 'do' block: input <- getLine
In the expression:
do { input <- getLine;
case (readMaybe input :: Maybe Float) of {
Just f -> f
Nothing -> do { ... } } }
In an equation for `getFloat':
getFloat
= do { input <- getLine;
case (readMaybe input :: Maybe Float) of {
Just f -> f
Nothing -> ... } }
Main.hs:42:56:
Couldn't match expected type `IO b0' with actual type `Float'
In the expression: f
In a case alternative: Just f -> f
Main.hs:43:60:
Couldn't match expected type `IO b0' with actual type `Float'
In a stmt of a 'do' block: getFloat
In the expression: do { getFloat }
I'm a beginner a would very much appreciate if someone could explain what am I missing here.
For the Just case, use -> return f instead of -> f.
And then just remove the type signature for getFloat. After it compiles, have ghci tell you what the type signature for getFloat is.
Complete code:
getFloat = do
input <- getLine
case (readMaybe input :: Maybe Float) of Just f -> return f
Nothing -> do getFloat
Update
You might be interested in this highly-polymorphic version of the loop:
{-# LANGUAGE NoMonomorphismRestriction #-}
import Text.Read
getItem = do
input <- getLine
case readMaybe input of
Nothing -> getItem
Just x -> return x
I have purposely written getItem without a type signature - this is something that GHC can infer and fill in for you. I've also used the NoMonomorphismRestriction pragma so that getItem remains polymorphic.
The idea is that getItem can be used for any type that can be read - Floats, Doubles, Strings, etc. The type used by readMaybe can be controlled by the caller in various ways. Here are some examples:
main = do
f1 <- getItem
f2 <- getItem
let r = f1 + f2 :: Float
print r
By forcing r to be type Float, f1 and f2 must also be Floats, and therefore getItem will try to parse a Float.
Here is another way to influence the type that readMaybe uses:
main = do
f <- getItem :: IO Float
i <- getItem :: IO Int
print $ f^i -- compute f raised to the i-th power
getFloat :: Float
This states that getFloat is a constant of type Float, which is not what you want.
getFloat :: IO Float
This instead states that getFloat is an IO action producing a Float.
Once this is fixed, then you need to add return in front of your f, as #ErikR already explained. The return turns the pure float value f into an IO action which produces it, without actually performing any IO.
Finally, you do not need the do in the last do getFLoat. The do syntax is useful to sequence IO actions: if you only have one, it is redundant.
I found the following Haskell code, but I'm confused:
main = putStrLn "Enter 1st String:"
>> getLine
>>= \a -> read a
What do the two "greater than" symbols (>>) mean? A new statement?
What do the two "greater than" symbols followed by an equal sign (>>=) mean?
This Haskell code throws the following error:
a.hs:3:13:
No instance for (Read (IO t0)) arising from a use of ‘read’
In the expression: read a
In the second argument of ‘(>>=)’, namely ‘\ a -> read a’
In the expression:
putStrLn "Enter 1st String:" >> getLine >>= \ a -> read a
1) does two greater than symbols mean a new statement?
In this context, yes. In the IO monad, >> is a rough equivalent of the ; in many imperative programming languages.
2) what does two greater than symbols followed by equal sign mean?
x >>= y is like x >> y except it takes the result of x and applies to y, which has to be a function. Briefly put, getLine >>= \a -> action means "read a line, bind that value to variable a, and run action (which can depend from a).
I'd recommend a monad tutorial to fully understand these. You can start with a general tutorial such as LYAH.
Your code is more commonly written in do notation:
main = do
putStrLn "Enter 1st String:"
a <- getLine
read a
where the last line makes no sense: read returns a value but does not do any I/O, so we can not chain that to a sequence of I/O actions. This triggers a compiler error. If you know some imperative programming, think about the pseudocode
print("some message");
a = inputLine();
toInteger(a);
The last line makes no sense: it converts the string into an integer... and then does not use the result in any way.
About your second question: your main is not a valid monadic expression. When specialised to the IO monad, the bind and then operators have type
(>>=) :: IO a -> (a -> IO b) -> IO b
(>>) :: IO a -> IO b -> IO b
If you try to align the types of your main expression, you will identify the problem very quickly:
putStrLn "Enter 1st String:" >> getLine >>= \a -> read a
{ IO () } {IO String} {actual: Read t => String -> t }
{ IO String } {expected: String -> IO t} ??? }
The type expected for the second argument of >>= is String -> IO t, but read doesn't return an IO value.
Alright so here's my current code:
import System.IO
import System.Environment
import System.Directory
main = do
unfiltered <- getArgs ; home <- getHomeDirectory ; let db = home ++ "/.grindstone"
case unfiltered of
(x:xs) -> return ()
_ -> error "No command given. See --help for more info."
command:args <- getArgs
createDirectoryIfMissing True db
let check = case args of
[] -> error "No arguments given. See --help for more info."
_ -> do let (params#(param:_),rest) = span (\(c:_) -> c=='-') args
if length params > 1 then error ("No arguments given for " ++ param)
else do
let (pArgs,_) = span (\(c:_) -> c/='-') rest
return (param, pArgs) :: Either (IO ()) (String, [String])
let add = print "sup"
let cmds = [("add", add)]
let action = lookup command cmds
case action of
Nothing -> error "Unknown command."
(Just action) -> action
The main problem is with check. I tried implementing the Either type since I want it to either error out, or return something for another function to use, but, it's currently erroring out with:
grindstone.hs:21:23:
No instance for (Monad (Either (IO ())))
arising from a use of `return' at grindstone.hs:21:23-43
Possible fix:
add an instance declaration for (Monad (Either (IO ())))
In the expression:
return (param, pArgs) :: Either (IO ()) (String, [String])
In the expression:
do { let (pArgs, _) = span (\ (c : _) -> ...) rest;
return (param, pArgs) :: Either (IO ()) (String, [String]) }
In the expression:
if length params > 1 then
error ("No arguments given for " ++ param)
else
do { let (pArgs, _) = ...;
return (param, pArgs) :: Either (IO ()) (String, [String]) }
I'm only starting out in haskell and haven't dealt too much with monads yet so just thought I'd ask on here. anyone have any ideas?
The error that is causing your compile problems is that you are directly casting an expression to the type Either (IO ()) (String, [String]) when it is not an Either value. (The compiler is not outputting a very helpful error message.)
To create an Either value [1], we use the data constructors Left and Right. Convention (from the library page) is that errors are a Left value, while correct values are a Right value.
I did a quick rewrite of your arg checking function as
checkArgs :: [String] -> Either String (String, [String])
checkArgs args =
case args of
[] -> Left "No arguments given. See --help for more info."
_ -> let (params#(param:_),rest) = span (\(c:_) -> c=='-') args in
if length params > 1 then
Left ("No arguments given for " ++ param)
else
let (pArgs,_) = span (\(c:_) -> c/='-') rest in
Right (param, pArgs)
Note that the arg checking function does not interact with any external IO () library functions and so has a purely functional type. In general if your code does not have monadic elements (IO ()), it can be clearer to write it in purely functional style. (When starting out in Haskell this is definitely something I would recommend rather than trying to get your head around monads/monad transformers/etc immediately.)
When you are a little more comfortable with monads, you may want to check out Control.Monad.Error [2], which can wraps similar functionality as Either as a monad and would encapsulate some details like Left always being computation errors.
[1] http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/Data-Either.html
[2] http://hackage.haskell.org/packages/archive/mtl/1.1.0.2/doc/html/Control-Monad-Error.html
Either (IO ()) (String, [String]) is a type that contains an IO action or a
(String, [String]), so values of this type could be Left IO () or
Right (String, [String]). Left values usually represents an error
occurrence in Haskell. This error can be represented with any type you want,
for example, an error code (Int) or a String that says what happened.
If you use IO () as the type which represents an error, you won't be able
to extract any information about the error. You just will able to perform an IO action later on.
The type that you are looking for isn't Either (IO ()) (String, [String]),
is Either String (String, [String]). With this type can get information about the
error (String). Now, you dont need any IO action into Either type, so you
can remove all do expressions:
let check = case args of
[] -> Left "No arguments given. See --help for more info."
_ -> let (params#(param:_),rest) = span (\(c:_) -> c=='-') args
in if length params > 1
then Left ("No arguments given for " ++ param)
else let (pArgs,_) = span (\(c:_) -> c/='-') rest
in Right (param, pArgs)