I am using guards inside a function but not immediately after the function signature. The guards are under a do statement inside the body of the function. I get this error:
parse error on input `|'
I thought maybe the error comes from the indentation but i have tried many indentation but still i get the errors. Am asking is it because the guards are not immedaitely after the function signature that is why am getting the errors?
thanks
UPDATE 1
CODE:
The user is suppose to guess a number , and the number will be compared with the random number if they are the same. If it is not correct then the user will guess till the "guess" variable in the function is zero. in every interation that value(guess) is decreased by one.
for instance : puzz 12 5. the user can guess for five times, the random number will be picked between 1 and 12. that is how the function is suppose to do, but it is not working.
puzz :: Int -> Int -> IO ()
puzz boundary guess = do
putStr "Guess"
-- putStr -- I have to print (1 .. guess) here in each iteration
putStr ":"
x <- randomRIO (1, boundary :: Int)
n <- getLine
let
nTo = read n::Int
in print x
| guess == 0 = putStr "You couldn't guess right,the correct answer is" ++ x
| nTo > x = putStr "lower"
| nTo < x = putStr "higer"
| nTo == x = putStr "Congrat, You guess right."
| otherwise raad boundary (guess - 1)
the ouput must be like this:
Main> puzz 50 6
Guess a number betwee 1 en 50.
Guess 1: 49
lower
Guess 2: 25
lower
Guess 3: 12
higher
Guess 4: 18
higher
Guess 5: 21
higher
Guess 6: 23
lower
You couldn't guess correct, the answer was: 22.
thanks for your help
You’re using guards incorrectly. From the report:
Top level patterns in case expressions and the set of top level patterns in function or pattern bindings may have zero or more associated guards.
So they’re only for cases and function bindings. If you just want to concisely introduce a series of true-false tests, while inside a do-notation, perhaps the case () of () trick would work:
main = do
putStrLn "hello world"
n <- getLine
let nTo = read n :: Int
case ()
of () | cond -> putStrLn "foo"
| cond' -> putStrLn "bar"
| otherwise -> putStrLn "baz"
It should be noted that there are several things that are a bit off with your code, in addition to using guards wrong. By default output is buffered in haskell so if you want Guess to be on the same line as input you have to either say that stdOut should not be buffered (hSetBuffering stdOut NoBuffering), or you have to flush output with hFlush. It's not necessary to write boundary :: Int, the compiler knows it is an Int. Here is a bit more complete example, I'm sure it could be done better but atleast it works:
import Control.Monad(liftM,unless)
import System.IO(hFlush,stdout)
import System.Random(randomRIO)
guessMyNumber upper guesses = do
putStrLn $ "Guess a number between 1 and " ++ show upper ++ "!"
randomRIO (1, upper) >>= puzz guesses
puzz 0 number = do
putStrLn $ "Sorry, no more guesses, the number was "
++ show number ++ "."
puzz guesses number = do
putStr "Guess:" >> hFlush stdout
guess <- liftM read getLine
printMessage guess number guesses
printMessage guess number guesses
| number > guess = putStrLn "higer" >> puzz (guesses-1) number
| number < guess = putStrLn "lower" >> puzz (guesses-1) number
| number == guess = putStrLn "Congratulations! You guessed right!"
Related
I want to write a simple game "guess number" - with n attempts. I want to add some conditions and hits. Is it possible to use guards inside do block ?
Here is my code:
game = return()
game n = do putStrLn "guess number: 0-99"
number<-getLine
let y = read number
let x =20
| y>x = putStrLn "your number is greater than x"
| y<x = putStrLn "your number is less than x"
| y==x putStrLn "U win!!"
| otherwise = game (n-1)
already got error
error: parse error on input ‘|’
Is it fixable with some white space, or just impossible to do?
A do expression [Haskell-report] only consists out of exp, pat <- exp, and let … statements, and the compiler will desugar these. Hence without some language extensions, you can not write guards in a do block. Furthermore it is likely not a good idea to enable that anyway. What if you for example would want to use two "guard blocks" next to each other? Then the two would "merge" and thus the guards of the first block would already eleminate (nearly) all cases.
You can use another let clause here:
game :: IO ()
game 0 = return ()
game n = do
putStrLn "guess number: 0-99"
number <- getLine
let y = read number
let x = 20
let action | y > x = putStrLn "your number is greater than x" >> game (n-1)
| y < x = putStrLn "your number is less than x" >> game (n-1)
| otherwise = putStrLn "U win!!"
action
Note that the otherwise in the original question will never get triggered, since a value is less than, greater than, or equal to another value.
Lots of problems there.
First, you can't say game = something and game n = something, so remove the game = return () line. (You may have been trying to write a type signature, but that's not one.)
Second, you can't drop into guard syntax in arbitrary places. The closest valid thing to what you wrote are multi-way if-expressions, which would let you write this:
{-# LANGUAGE MultiWayIf #-}
game n = do putStrLn "guess number: 0-99"
number<-getLine
let y = read number
let x =20
if
| y>x -> putStrLn "your number is greater than x"
| y<x -> putStrLn "your number is less than x"
| y==x-> putStrLn "U win!!"
| otherwise -> game (n-1)
Third, the Ord typeclass is supposed to be for types with a total order, so unless you're using unlawful things like NaN, you'll always have one of y>x, y<x, or y==x, so the otherwise will never be entered.
Fourth, comparing with <, ==, and > is unidiomatic and slow, since it has to keep repeating the comparison. Instead of doing that, do something like this:
case y `compare` x of
GT -> _
LT -> _
EQ -> _
You could also just use case or LambdaCase.
{-# LANGUAGE LambdaCase #-}
game :: Int -> IO ()
game n = case n of
0 -> putStrLn "used all attempts"
n ->
putStrLn "guess a number: 0 - 99" >>
(`compare` 20) . read <$> getLine >>=
\case
EQ -> putStrLn "U win"
GT -> putStrLn "your number is greater than x" >>
game (n - 1)
LT -> putStrLn "your number is less than x" >>
game (n - 1)
The other answers are very informative. Reading those led me to see that you can also call a function to solve this, e.g.
game = do putStrLn "guess number: 0-99"
number <- getLine
let y = read number
let x = 20
action y x
where
action y x
| y>x = putStrLn "your number is greater than x" >> game
| y<x = putStrLn "your number is less than x" >> game
| otherwise = putStrLn "U win!!"
Below if my code right now. I want to be able to take in user input like the following: "6 1 2 3 4 5 6" and the get the sum and print. it would also be cool to understand how to use the first number entered as the total numbers. SO here the first number is 6 and the total numbers inputted is 6.
Thank you in advance for helping me with this. I have been researching for weeks and cannot figure this out.
main = do
putStrLn "Enter how many numbers:" -- clearer
num<-getLine
putStrLn("Enter a number: ")
numberString <- getLine
let numberInt =(read numberString :: Int)
print (numberInt*4)
main
It seems you either need an auxiliary recursive function for reading num integers, or some helper like replicateM, which makes writing the code a little easier.
replicateM num action runs action exactly num times, and collects all the action results in a list.
main = do
putStrLn "Enter how many numbers:" -- clearer
num<-getLine
numbers <- replicateM num $ do
putStrLn("Enter a number: ")
numberString <- getLine
return (read numberString :: Int)
-- here we have numbers :: [Int]
...
You can then continue from there.
If instead you want to use an auxiliary function, you can write
readInts :: Int -> IO [Int]
readInts 0 = return []
readInts n = do
putStrLn("Enter a number: ")
numberString <- getLine
otherNumbers <- readInts (n-1) -- read the rest
return (read numberString : otherNumbers)
Finally, instead of using getLine and then read, we could directly use readLn which combines both.
Construct a list of integers using
let l = map (\x -> read x::Int) (words "6 1 2 3 4 5 6")
in (numNumbers, numbers)
You tried to read the whole string into a single number.
I have a question that asks me find 'quadratic equation' and show result and add number of the roots
example:
Main> quadratric 2 2 2
2x^2 + 2x + 2 = 0
Has no real roots.
Main> quadratic 2 5 2
2x^2 + 5x + 2 = 0
Has two real roots:
-2.0 and -0.5
So this is quadratic equation:
quadraticprob a b c
| root < 0 = error "Has no real roots"
| root == 0 = [-b/(2*a)]
| root > 0 = [-b/(2*a) + sqroot/(2*a),
-b/(2*a) - sqroot/(2*a)]
where
root = b*b - 4*a*c
sqroot = sqrt root
I can get the result but I should add how many roots they have so I should use one more function that getLine and show the result.
I made this but it's totally wrong:
readresult :: IO ()
readresult = do
line <- getLine
putStrLn (show (quadraticprob (read line))
Can you help me with my mistake please?
Assume you want get 3 integers from standard input call "getLine" function once.
The expression
line <- getLine
will return a string like (for example)
"2 2 2"
with spaces between each integer. The first thing need to do is to remove the space and convert it from string to Int type. the words and read functions can solve this easily as below:
map read (words line)::[Int]
However, a integers list cannot pass to your quadratic function directly, it need use case get elements from list as below
case map read (words line)::[Int] of
[a, b, c] -> putStrLn $ show $ quadraticprob a b c
If you want read real number instead of integers, just change map..::[Int] to ::[Double].
A few hints:
Use a getLine for each argument
... = do
astr <- getLine
bstr <- getLine
cstr <- getLine
putStrLn (show (quadraticprob (read astr) (read bstr) (read cstr)))
For quadraticprob, it's not clear what your goal actually is. Before writing any code, you should start by writing the intended type.
quadraticprob :: ?? -> ?? -> ?? -> ??
What should that be?
I have written a Haskell code as:
loop = do
x <- getLine
if x == "0"
then return ()
else do arr <- replicateM (read x :: Int) getLine
let blocks = map (read :: String -> Int) $ words $ unwords arr
putStr "Case X : output = "; -- <- What should X be?
print $ solve $ blockPair blocks;
loop
main = loop
This terminates at 0 input. I also want to print the case number eg. Case 1, 2 ...
Sample run:
1
10 20 30
Case 1: Output = ...
1
6 8 10
Case 2: Output = ...
0
Does anyone know how this can be done? Also, If possible can you suggest me a way to print the output line at the very end?
Thanks in advance.
For the first part of your question, the current case number is an example of some "state" that you want to maintain during the course of your program's execution. In other languages, you'd use a mutable variable, no doubt.
In Haskell, there are several ways to deal with state. One of the simplest (though it is sometimes a little ugly) is to pass the state explicitly as a function parameter, and this will work pretty well given the way you've already structured your code:
main = loop 1
loop n = do
...
putStr ("Case " ++ show n ++ ": Output = ...")
...
loop (n+1) -- update "state" for next loop
The second part of your question is a little more involved. It looks like you wanted a hint instead of a solution. To get you started, let me show you an example of a function that reads lines until the user enters end and then returns the list of all the lines up to but not including end (together with a main function that does something interesting with the lines using mostly pure code):
readToEnd :: IO [String]
readToEnd = do
line <- getLine
if line == "end"
then return []
else do
rest <- readToEnd
return (line:rest)
main = do
lines <- readToEnd
-- now "pure" code makes complex manipulations easy:
putStr $ unlines $
zipWith (\n line -> "Case " ++ show n ++ ": " ++ line)
[1..] lines
Edit: I guess you wanted a more direct answer instead of a hint, so the way you would adapt the above approach to reading a list of blocks would be to write something like:
readBlocks :: IO [[Int]]
readBlocks = do
n <- read <$> getLine
if n == 0 then return [] else do
arr <- replicateM n getLine
let block = map read $ words $ unwords arr
blocks <- readBlocks
return (block:blocks)
and then main would look like this:
main = do
blocks <- readBlocks
putStr $ unlines $
zipWith (\n line -> "Case " ++ show n ++ ": " ++ line)
[1..] (map (show . solve . blockPair) blocks)
This is similar in spirit to K. A. Buhr's answer (the crucial move is still passing state as a parameter), but factored differently to demonstrate a neat trick. Since IO actions are just normal Haskell values, you can use the loop to build the action which will print the output without executing it:
loop :: (Int, IO ()) -> IO ()
loop (nCase, prnAccum) = do
x <- getLine
if x == "0"
then prnAccum
else do inpLines <- replicateM (read x) getLine
let blocks = map read $ words $ unwords inpLines
prnAccumAndNext = do
prnAccum
putStr $ "Case " ++ show nCase ++ " : output = "
print $ solve $ blockPair blocks
loop (nCase + 1, prnAccumAndNext)
main = loop (1, return ())
Some remarks on the solution above:
prnAccum, the action which prints the results, is threaded through the recursive loop calls just like nCase (I packaged them both in a pair as a matter of style, but it would have worked just as fine if they were passed as separate arguments).
Note how the updated action, prnAccumAndNext, is not directly in the main do block; it is defined in a let block instead. That explains why it is not executed on each iteration, but only at the end of the loop, when the final prnAccum is executed.
As luqui suggests, I have removed the type annotations you used with read. The one at the replicateM call is certainly not necessary, and the other one isn't as well as long as blockPair takes a list of Int as an argument, as it seems to be the case.
Nitpicking: I removed the semicolons, as they are not necessary. Also, if arr refers to "array" it isn't a very appropriate name (as it is a list, and not an array), so I took the liberty to change it into something more descriptive. (You can find some other ideas for useful tricks and style adjustments in K. A. Buhr's answer.)
I have the following simple number guess program
import System.Random
turn :: Int -> Int -> Int -> IO ()
turn number attempt attempts =
do
if attempts == 0
then putStrLn "You lose"
else if attempt==number
then putStrLn "You got it!"
else if attempt==0
then guess number attempt attempts
else if attempt < number
then do
putStrLn "The number is greater"
guess number attempt attempts
else
do
putStrLn "The number is lesser"
guess number attempt attempts
guess :: Int -> Int -> Int -> IO ()
guess number attempt attempts =
do
putStr "Try and guess number "
g <- getLine
let number' = read g :: Int
let check = (number'==number)
let attempts' = if check then attempts else attempts - 1
turn number number' attempts'
numberGuess :: IO ()
numberGuess = do
let attempts = 5
number <- randomRIO (0, 10) :: IO Int
turn number 0 attempts
How can I clean up the ugly if else or what techniques are available in haskell?
Your outermost do in turn doesn't actually do anything. So you should nix it. Next, use pattern matching and guards to begin to clean things up.
turn _number _attempt 0 = putStrLn "You lose"
turn number attempt attempts
| attempt == number = putStrLn "You got it!"
| attempt == 0 = guess number attempt attempts
| attempt < number = do
putStrLn "The number is greater"
guess number attempt attempts
| otherwise = do
putStrLn "The number is lesser"
guess number attempt attempts
The final step to clean up turn will be factoring out the pattern "Do something, then call guess". I'll let you try that on your own. I used a pattern match for the first case to demonstrate that technique, which is very often the right one. In this particular case you might be better off just using guards.
For guess, the easy bit is just to combine some expressions.
guess :: Int -> Int -> Int -> IO ()
guess number attempt attempts = do
putStr "Try and guess number "
g <- getLine
let attempts' = if read g == number
then attempts
else attempts - 1
turn number number' attempts'
Note, however, that read generally shouldn't be used to process user input, as it will crash your program on bad input. Import Text.Read and use readMaybe, perhaps.