Consider this code:
import Text.ParserCombinators.ReadP
prefixExpr :: ReadP Int
prefixExpr = choice [readPlus, readS_to_P reads]
where
readPlus = do
string "+ "
s1 <- prefixExpr
string " "
s2 <- prefixExpr
return $ s1 + s2
p $. s = case [ x | (x,"") <- p `readP_to_S` s ] of
[x] -> Right x
[ ] -> Left "mkRead: no parse"
_ -> Left "mkRead: ambiguous parse"
It works great!
λ prefixExpr $. "+ 1 + 2 3"
Right 6
But this variant does not:
infixExpr :: ReadP Int
infixExpr = choice [readPlus, readS_to_P reads]
where
readPlus = do
s1 <- infixExpr
string " + "
s2 <- infixExpr
return $ s1 + s2
Actually, it hangs.
λ infixExpr $. "1 + 2 + 3"
^CInterrupted.
λ infixExpr $. "1"
^CInterrupted.
I understand that infixExpr enters infinite recursion trying to decide whether "1" is a number
or the start of an expression, but I wonder how I can prevent that. I do not really need my
program to explore all the possibilities indefinitely, just to pick the most obvious one and disregard
the others altogether. How can I do that?
One thing I tried is to put a restriction on the recursive depth.
infixExpr :: Int -> ReadP Int
infixExpr 0 = number
infixExpr n = choice [plus, number]
where
plus = do
s1 <- infixExpr (n - 1)
string " + "
s2 <- infixExpr (n - 1)
return $ s1 + s2
It kind of works, but it is practically useless because of its exponential complexity.
As suggested by #chi, removing left recursion through factorization:
infixExpr :: ReadP Int
infixExpr = number >>= \x -> choice [plus x, eof >> return x]
where
plus x = do
string " + "
y <- infixExpr
return $ x + y
It works:
λ infixExpr $. "1"
Right 1
λ infixExpr $. "1 + 2"
Right 3
λ infixExpr $. "1 + 2 + 3"
But I am a bit unhappy about it. I would rather that the original grammar was made to work, because it looks more like human thinking than this one.
To be fair, the same effect could be achieved easier, by a very small edit:
infixExpr :: ReadP Int
infixExpr = choice [plus, number]
where
plus = do
s1 <- number -- Notice!
string " + "
s2 <- infixExpr
return $ s1 + s2
I figured it some time ago, but I really wanted to have this symmetry to the definition of plus.
Related
While trying to implement the famous Ackermann function in Haskell to test whether the promised difference in running time is actually measurable, I stumbled across this beauty of an error description:
Parse error in pattern: a - 1
Possibly caused by a missing 'do'?
I know that this parsing error is appearing pretty commonly and I have no idea why it does so.
Other than that, my code (see below) should be fine.
My code:
main :: IO ()
main = do
print "Please enter first operand: "
input <- getLine
let n = read input
print "Please enter second operand: "
input <- getLine
let m = read input
let r = ak(n,m)
print(n++" ackermann "++m++" = "++show r)
ak(a,b) = do
if a == 0
then return (b+1)
else if b == 0
then return ak(a-1, 1)
else
s1 <- ak(a-1, b)
s2 <- ak(a-1, s1)
return s2
Don't use do and return for ak. do blocks are used for monadic computations. You can work with:
ak 0 b = b + 1
ak a 0 = ak (a-1) 1
ak a b = ak (a-1) (ak a (b-1))
Then you can implement main as:
main :: IO ()
main = do
print "Please enter first operand: "
n <- readLn
print "Please enter second operand: "
m <- readLn
putStrLn (show n ++ " ackermann " ++ show m ++ " = " ++ show (ak n m))
I want to display some Rational values in their decimal expansion. That is, instead of displaying 3 % 4, I would rather display 0.75. I'd like this function to be of type Int -> Rational -> String. The first Int is to specify the maximum number of decimal places, since Rational expansions may be non-terminating.
Hoogle and the haddocks for Data.Ratio didn't help me. Where can I find this function?
You can make it. Not elegant, but does the job:
import Numeric
import Data.Ratio
display :: Int -> Rational -> String
display n x = (showFFloat (Just n) $ fromRat x) ""
Here is an arbitrary precision solution that doesn't use floats:
import Data.Ratio
display :: Int -> Rational -> String
display len rat = (if num < 0 then "-" else "") ++ (shows d ("." ++ take len (go next)))
where
(d, next) = abs num `quotRem` den
num = numerator rat
den = denominator rat
go 0 = ""
go x = let (d, next) = (10 * x) `quotRem` den
in shows d (go next)
Arbitrary precision version that re-uses library code:
import Data.Number.CReal
display :: Int -> Rational -> String
display digits num = showCReal digits (fromRational num)
I know I've seen a function before that converts rationals into digits in a way that's easier to inspect (i.e. that makes it quite clear where the digits start repeating), but I can't seem to find it now. In any case, it's not hard to write, if that turns out to be a need; you just code up the usual long-division algorithm and watch for divisions you've already done.
Here's one that I wrote a few weeks ago. You can specify the number of decimals you want (correctly rounded), or just pass Nothing in which case it will print the full precision, including marking the repeated decimals.
module ShowRational where
import Data.List(findIndex, splitAt)
-- | Convert a 'Rational' to a 'String' using the given number of decimals.
-- If the number of decimals is not given the full precision is showed using (DDD) for repeating digits.
-- E.g., 13.7/3 is shown as \"4.5(6)\".
showRational :: Maybe Int -> Rational -> String
showRational (Just n) r =
let d = round (abs r * 10^n)
s = show (d :: Integer)
s' = replicate (n - length s + 1) '0' ++ s
(h, f) = splitAt (length s' - n) s'
in (if r < 0 then "-" else "") ++ h ++ "." ++ f
-- The length of the repeating digits is related to the totient function of the denominator.
-- This means that the complexity of computing them is at least as bad as factoring, i.e., it quickly becomes infeasible.
showRational Nothing r =
let (i, f) = properFraction (abs r) :: (Integer, Rational)
si = if r < 0 then "-" ++ show i else show i
decimals f = loop f [] ""
loop x fs ds =
if x == 0 then
ds
else
case findIndex (x ==) fs of
Just i -> let (l, r) = splitAt i ds in l ++ "(" ++ r ++ ")"
Nothing -> let (c, f) = properFraction (10 * x) :: (Integer, Rational) in loop f (fs ++ [x]) (ds ++ show c)
in if f == 0 then si else si ++ "." ++ decimals f
import Data.List as L
import Data.Ratio
display :: (Integral i, Show i) => Int -> Ratio i -> String
display len rat = (if num < 0 then "-" else "") ++ show ip ++ "." ++ L.take len (go (abs num - ip * den))
where
num = numerator rat
den = denominator rat
ip = abs num `quot` den
go 0 = ""
go x = shows d (go next)
where
(d, next) = (10 * x) `quotRem` den
This is to take a number, get its factorial and double it, however because of the base case if you input 0 it gives 2 as the answer so in order to bypass it i used an if statement, but get the error
parse error on input ‘if’. Really appreciate if you guys could help :)
fact :: Int -> Int
fact 0 = 1
fact n = n * fact(n-1)
doub :: Int -> Int
doub r = 2 * r
factorialDouble :: IO()
factorialDouble = do
putStr "Enter a Value: "
x <- getLine
let num = (read x) :: Int
if (num == 0) then error "factorial of zero is 0"
else let y = doub (fact num)
putStrLn ("the double of factorial of " ++ x ++ " is " ++ (show y))
I've spotted two issues
that should be addressed
You have a let that has no continuation:
(else let y = doub (fact num) ...).
Because you're not inside a do, you would probably want to change it into a let ... in statement.
Your if is indented too far in. It should be under the let.
I've corrected what I mentioned and the code works for me...
fact :: Int -> Int
fact 0 = 1
fact n = n * fact(n-1)
doub :: Int -> Int
doub r = 2 * r
factorialDouble :: IO ()
factorialDouble = do
putStr "Enter a Value: "
x <- getLine
let num = (read x) :: Int
if num == 0 then (error "factorial of zero is 0")
else let y = doub (fact num)
in putStrLn ("the double of factorial of " ++ x ++ " is " ++ (show y))
I have written the following to assist grand kids with their home schooling work and to keep mind working by learning how to program (I thought haskell sounded awesome).
main :: IO ()
main = do
putStrLn "Please enter the dividend :"
inputx <- getLine
putStrLn "Please enter the divisor :"
inputy <- getLine
let x = (read inputx) :: Int
let y = (read inputy) :: Int
let z = x `div` y
let remain = x `mod` y
putStrLn ( "Result: " ++ show x ++ " / " ++ show y ++ " = " ++ show z ++ " remainder " ++ show remain )
putStrLn ( "Proof: (" ++ show y ++ " x " ++ show z ++ ") = " ++ show (y * z) ++ " + " ++ show remain ++ " = " ++ show ((y * z) + remain))
putStrLn ( "Is this what you had? ")
Is their a neater/nicer/better/more compact way of doing this?
It would benefit from a key principle: separate your pure code from your IO as much as possible. This will let your programs scale up and keep main breif. Lots of let in a big main isn't a very functional approach and tends to get much messier as your code grows.
Using a type signature and readLn which is essentially fmap read getLine helps cut down some cruft. (If you're not familiar with fmap, visit the question How do functors work in haskell?. fmap is a very flexible tool indeed.)
getInts :: IO (Int, Int)
getInts = do
putStrLn "Please enter the dividend :"
x <- readLn
putStrLn " Please enter the divisor :"
y <- readLn
return (x,y)
Now the processing. If I were doing more with this kind of data, or more frequently, I'd be using a record type to store the dividend, divisor, quotient and remainder, so bear that in mind for the future, but it's an overkill here.
I'm hackishly returning a list rather than a tuple, so I can use map to show them all:
sums :: (Int, Int) -> [Int]
sums (x,y) = [x, y, q, r, y * q, y * q + r] where
q = x `div` y
r = x `mod` y
The final piece of the jigsaw is the output. Again I prefer to generate this outside IO and then I can just mapM_ putStrLn on it later to print each line. I'd prefer this to take the record type, but I'm tolerating a list of strings as input instead since I'm assuming I've already shown them all.
explain :: [String] -> [String]
explain [x,y,q,r,yq,yq_r] =
[ concat ["Result: ", x, " / ", y, " = ", q, " remainder ", r]
, concat ["Proof: (", y, " x ", q, ") + ", r, " = ", yq, " + ", r, " = ", yq_r]
, "Is this what you had? "]
Now we can write main as
main = do (x,y) <- getInts
let ns = map show ( sums (x,y) )
es = explain ns
mapM_ putStrLn es
or even more succinctly, by piping together the functions explain . map show . sums, and applying that to the output of getInts using fmap:
main :: IO ()
main = fmap (explain . map show . sums) getInts
>>= mapM_ putStrLn
You might notice that I added a +r in the proof to make = always mean =, which is the correct mathematical usage, and mirror's Haskell's meaning for =.
I'm still trying to solve an issue I have with string formatting and I just can't seem to get it working.
I have two functions that give me Integers out as they are just calculations and I want to create a string with these two calculations in a third and new output AND make it nice and pretty. I'd like to present it in like a table (colums and rows).
What I am trying so far is:
tableShow :: Int -> Int -> String
tableShow n 0 = putStrLn (n power1 power2)
tableShow n k
| let list_k = [0..k]
| k > 0 = show(unlines[n ++ "\t" calc1 x k ++ "\t" ++ "\t" ++ calc2 x k | x <- list_k])
calc1 and calc2 just take two Integers given by user and do a simple calculation on them, returning a value. At least I got those working like a charm. :)
Anyone have a good idea where I am going wrong?!? Is there someone who can point me in the right direction?
Any and all ideas and suggestions will be greatly appreciated, I've been at this all weekend now :/
//regards
tableShow :: Int -> Int -> String
tableShow n 0 = putStrLn (n power1 power2)
tableShow n k
| let list_k = [0..k]
| k > 0 = show(unlines[n ++ "\t" calc1 x k ++ "\t" ++ "\t" ++ calc2 x k | x <- list_k])
You didn't mention whether your problem was an error or just that your function doesn't work as intended, but your let binding syntax is off, and you missed a ++. I don't know what you intended for n power1 power2, but I'll guess that you wanted multiplication. It should be:
tableShow :: Int -> Int -> String
tableShow n 0 = putStrLn (n * power1 * power2)
tableShow n k
| k > 0 = let list_k = [0..k] in
show(unlines[n ++ "\t" ++ calc1 x k ++ "\t" ++ "\t" ++ calc2 x k | x <- list_k])
You may want to look over a tutorial or two to get the syntax down.
To turn basic values like Ints into Strings, use show.
multMsg x y = "The product of " ++ show x ++ " and " ++ show y ++ " is " ++ show (x*y)
I usually use concat in this situation though.
multMsg2 x y = concat ["The product of ", show x, " and ", show y, " is ", show (x*y)]