I would like to do something different but it would be too long so below is only example:
test x y = if x == "5" then x
else do putStrLn "bad value"; y
so if x == 5 it should return x, else it should print 'bad value' and return y - how can I do that in haskell ?
edit:
Why this code returns error: "couldn't match expected type bool with actual type IO bool" ?
canTest :: String -> IO Bool
canTest x = if x == "5" then return True
else do putStrLn "bad value"; return False
test x y = if canTest x then x
else y
You need to make both sides have the same type, namely IO String. For this you need to use return to lift the values into the monad, i.e.
test :: String -> String -> IO String
test x y = if x == "5"
then return x
else do putStrLn "bad value"
return y
Now return x has the type IO String, and so does the do block in the else branch.
Because canTest has side-effects (i.e. does I/O), its return type is IO Bool, which has two implications:
You cannot test its value directly in the if predicate, you must 'run' the action first, then test the extracted value.
Your edited test function must also be in the IO monad, as you cannot escape IO. (Unless very carefully with unsafePerformIO)
canTest :: String -> IO Bool
canTest x = if x == "5"
then return True
else do putStrLn "bad value"; return False
test :: String -> String -> IO String
test x y = do xCanTest <- canTest x
if xCanTest
then return x
else return y
Results in
Prelude> test "5" "12"
"5"
Prelude> test "6" "12"
bad value
"12"
Related
Why is this function allowed:
-- function 1
myfunc :: String
myfunc = do
x <- (return True)
show x
and this is not:
-- function 2
myfunc :: String
myfunc = do
x <- getLine
show x
The compile error:
Couldn't match type `[]' with `IO'
Expected type: IO Char
Actual type: String
I get why function 2 shouldn't work, but why then thus function 1 work?
and why does this then work:
-- function 3
myfunc = do
x <- getLine
return (show x)
I get that it returns IO String then, but why is function 1 also not forced to do this?
In function1 the do block in myfunc is working in the list monad, because String is really just [Char]. In there, return True just creates [True]. When you do x <- return True that "extracts" True out of [True] and binds it to x. The next line show x converts True into a String "True". which being the return value the compiler value expects to see, ends up working fine.
Meanwhile in function2, the do block in myfunc is also working on the list monad (for the same reason, String being really [Char]) but calls on getLine which is only available in the IO monad. So unsurprisingly, this fails.
-- EDIT 1
OP has added a function3
-- function 3
myfunc :: String
myfunc = do
x <- getLine
return (show x)
No this should not work for the same reason function2 fails.
-- EDIT 2
OP has updated function3 to fix a copy paste error.
-- function 3
myfunc = do
x <- getLine
return (show x)
This is mentioned in the comments, but for clarity sake, this works because, when the type information is unspecified, GHC makes it best inference and after seeing getLine, it figures it’s IO String which does provide getLine.
Note - I wrote this answer with as casual a tone as I could manage without being wrong with the intention of making it approachable to a beginner level.
do blocks work in the context of an arbitrary Monad. The Monad, in this case, is []. The Monad instance for lists is based on list comprehensions:
instance Monad [] where
return x = [x]
xs >>= f = [y | x <- xs, y <- f x]
You can desugar the do notation thus:
myfunc :: String
myfunc = do
x <- (return True)
show x
-- ==>
myfunc = [y | x <- return True, y <- show x]
-- ==>
myfunc = [y | x <- [True], y <- show x]
In a list comprehension, x <- [True] is really just the same as let x = True, because you're only drawing one element from the list. So
myfunc = [y | y <- show True]
Of course, "the list of all y such that y is in show True" is just show True.
I'm attempting to write a function that will continually loop checking if a randomly generated int is less than 5, if it is less than 5 then "e" is appended to a string, once "eee" is generated then exit out of the loop.
This Haskell code prints if a random value between 1 - 10 is less than 5 :
useInt :: Int -> Int
useInt x = x
test :: IO ()
test = do
let l = "eee";
int <- randomRIO (1, 10) :: IO Int
if(int < 5) then
putStrLn "less"
else
putStrLn "greater"
test
But I'm unsure how to modify a string without introducing mutable state.
To achieve this using pseudo haskell code can use :
var mutableString = "" :
useInt :: Int -> Int
useInt x = x
test :: IO ()
test = do
let l = "eee";
int <- randomRIO (1, 10) :: IO Int
while(mutableString != "eee"){
if(mutableString == "eee")
break out of loop
else
if(int < 5) then
mutableString = mutableString + "e"
putStrLn "less"
else
putStrLn "greater"
}
test
Any pointers to translate above pseudo code to valid Haskell ?
Use recursion:
test :: IO ()
test = let
loop "eee" = putStrLn "ending" -- end of the "loop"
loop l = do -- "loop" iteration
int <- randomRIO (1, 10) :: IO Int
if int < 5
then do
putStrLn "less"
loop l -- same value for l
else do
putStrLn "greater"
loop ('e':l) -- updated value for l
in loop "" -- "loop" start with initial value for l
The idea is that loop l takes as a parameter the current value of the "mutable" l. When we recurse, we pass the new value of l. In the then branch above we pass the same value since we don't want to modify it. In the else branch we prepend an 'e' character.
I don't understand this type error:
Couldn't match expected type `[t0]' with actual type `IO ()'
In the return type of a call of `printv'
In a stmt of a 'do' expression: px <- printv x
In the expression:
do { px <- printv x;
sep <- print ", ";
rest <- prints xs;
return (px : sep : rest) }
From:
data Value = IntValue Int
| TruthValue Bool
deriving (Eq, Show)
printv :: Value -> IO()
printv (IntValue i) = print i
printv (TruthValue b) = print ("boolean" ++ show b)
prints :: [Value] -> [IO()]
prints [] = []
prints (x:xs) = do px <- printv x
sep <- print ", "
rest <- prints xs
return (px:sep:rest)
It looks to me like every element (px) is converted into an IO() action, and then that is added to a list of the same things, thus producing an [IO()] list.
What am I missing here? Converting it to a list of strings, by removing the print's, works fine.
You're missing the return on the [] case of prints:
prints [] = return []
However, your prints is very strange. It returns a [()], because print is outputting strings to the console, not returning them.
Do you mean to return strings from your printv function?
Since you're trying to pretty print a syntax tree, here's roughly the right way to do it:
Use pretty-printing combinators
Use a pretty typeclass
Like so:
import Text.PrettyPrint
import Data.List
data Value
= VInt Int
| VBool Bool
deriving (Eq, Show)
class Pretty a where
pretty :: a -> Doc
instance Pretty Value where
pretty (VInt i) = int i
pretty (VBool b) = text "Boolean" <+> text (show b)
draw :: [Value] -> String
draw = intercalate ", " . map (render.pretty)
main = putStrLn $ draw [VInt 7, VBool True, VInt 42]
Running it:
*A> main
7, Boolean True, 42
Take a closer look at the type of your function:
prints :: [Value] -> [IO()]
But if we now take a look at prints [] = [], this can't match, because the type of that one is
prints :: [t] -> [a]
Therefore, you missed using prints [] = return [], to make it work.
If you're not evaluating an IO action, you don't need a do block. Just treat IO () as a normal type.
prints (x:xs) = printv x : print ", " : prints xs
You don't want prints to return an array of IO actions. You want it to return a single IO action that represents each of the IO actions bound together. Something like:
prints xs = mapM_ (\x -> printv x >> putStr ", ") xs
Except that I don't think the new lines are going to end up where you want them.
Look at the documentation for mapM and sequence for more information. In particular, the implementation of sequence is probably similar to what you're trying to do.
However, I would really recommend that instead doing all the work in an IO function, you should write a pure function to render the textual format you want, and then just print that. In particular, it seems that an instance of Show for Value would be appropriate.
instance Show Value where
show (IntValue i) = show i
show (TruthValue b) = "boolean " ++ show b
That way you can just call print value rather than printv value, and if you really wanted to you could define prints as follows.
import Data.List
prints :: (Show a) => [a] -> IO ()
prints = putStrLn . intercalate ", " . map show`.
I want to include more than one case statement in a Haskell function (see below for an example of a hypothetical function).
However, it is not legal Haskell. What is a better way of accomplishing the same thing? Furthermore, if the case statements are not returning anything, but simply setting some value, why is it not legal to have more than one case statement in a function?
(I would get a "parse error on input `case'" on line 5)
tester x y =
case (x < 0) of
True -> "less than zero."
False -> "greater than or equal to zero."
case (y == "foo")
True -> "the name is foo."
False -> "the name is not foo."
Note that if my function were simply:
tester x y =
case (x < 0) of
True -> "less than zero."
False -> "greater than or equal to zero."
...then it would compile.
In general the body of a function has to be a single expression (very often made up of smaller expressions). The following isn't allowed, for example:
f x y =
"foo"
"bar"
This is equivalent to your first example—we've just substituted one kind of expression (string literals) for another (your case expressions).
It's certainly possible to include more than one case expression in a Haskell function:
tester :: Int -> String -> (String, String)
tester x y = (a, b)
where
a = case (x < 0) of
True -> "less than zero."
False -> "greater than or equal to zero."
b = case (y == "foo") of
True -> "the name is foo."
False -> "the name is not foo."
Or even:
tester :: Int -> String -> IO ()
tester x y = do
putStrLn $ case (x < 0) of
True -> "less than zero."
False -> "greater than or equal to zero."
putStrLn $ case (y == "foo") of
True -> "the name is foo."
False -> "the name is not foo."
These work because the body of the function is a single expression (although neither is really idiomatic Haskell).
I wouldn't use a case statement in this case though, this IMO looks better:
tester :: Int -> String -> String
tester x y | x < 0 = "less than zero. " ++ expr
| otherwise = "greater than or equal to zero. " ++ expr
where expr = if y == "foo" then "the name is foo." else "the name is not foo."
In general, it looks like what you want is guards. However, as already mentioned, your function is not a single expression. Assuming that you want to return a tuple of strings, it can be written like this using guards (and some added fun from Arrows):
import Control.Arrow
testx x | x < 0 = "Less then zero."
| otherwise = "Greater then or equal to zero."
testy y | y == "foo" = "The name is foo."
| otherwise = "The name is not foo."
tester = curry (testx *** testy)
You could also drop the Control.Arrow bit all together and write:
tester x y = (testx x, testy y)
//edit 5
when the i use only these 2 lines
index :: [String] -> [String] -> Bool
index a b = and [x `elem` a |x <- b]
it works fine!!!!
eg:
index ["asd","asdd","dew"] ["asdd","asdad"]
False
But when i use the entire code mentioned below
empty [] = True
empty _ = False
index a b = do
if empty a
then do putStrLn "a is empty"
else return ()
if empty b
then do putStrLn "b is empty"
else return ()
where
index :: [String] -> [String] -> Bool
index a b = and [x `elem` a |x <- b]
theres no output!! and thats the issue i got!!
//edit 6
index a b = do index'
if empty a
then do putStrLn "a is empty"
else return ()
if empty b
then do putStrLn "b is empty"
else return ()
where
index' :: [String] -> [String] -> Bool
index' a b = and [x `elem` a |x <- b]
thanks
This is a little off-topic since maybe you are trying to learn the layout rule and how to nest ifs, but the code you show in revision 6 is just using if to do error checking. I would just do the error checking via pattern matching instead of if.
index [] _ = putStrLn "a is empty"
index _ [] = putStrLn "b is empty"
index a b = putStrLn (show index')
where index' = and [x `elem` a | x <- b]
(You don't need the return () after putStrLn because it already returns () for you.)
Pattern matching is a lot easier to get right because it doesn't require a lot of indentation, etc.
Edit:
I changed the definition of index' a little from yours. In my version it's a local variable instead of a local function. In Haskell, there's not much difference, it's just that index' uses a and b from the surrounding index function, so it doesn't need to take parameters. (Admittedly, index' is not such a good name for a variable.)
Also I left off the type annotation because I don't usually write them. But they are helpful when something isn't working. Here is what it would look like:
where index' :: Bool
index' = and [x `elem` a | x <- b]
An if construct in Haskell is a expression.
That means it must always evaluate to a value, so the else part is mandatory.
Also, the first part of if must be a boolean, so you can't call index' there, since that returns a [Int], not a Bool.
I would say, start with something like this:
if isEmpty a
then putStrLn "a is empty"
else if isEmpty b
then putStrLn "b is empty"
else putStrLn "neither are empty"
index a b = if index' [] bs
then putStrLn "a is empty"
if index' a []
then putStrLn "b is empty"
else
where
index' :: [String] -> [String] -> [Int]
index' a b = index' True [(elem x b) | x <- a]
If you indent your statement like this you'll see that the first if has no matching else clause.
Also, else clause doesn't return anything — a function should have a return value under all circumstances.
IO operations in Haskell are a bit difficult because they need so called monads
You would need a special do-notion here to sequence the outputs.
Write it like this:
empty [] = True
empty _ = False
index a b = do
if empty a
then do putStrLn "a is empty"
else return ()
if empty b
then do putStrLn "b is empty"
else return ()
Or Maybe you could just return the strings and use putStrLn separately.
You index' must return a boolean value when it should be used as an if condition!