Formatting strings in a table - haskell

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)]

Related

Print Custom String With the Sum of Three Lists

When I run the following code:
main = do
let smallTriplets xs ys zs = [ (x, y, z) | x <- xs, y <- ys, z <- zs, let sum = x + y + z, sum <= 10]
print (smallTriplets [1,2] [3,4] [5,6])
It gives the output:
[(1,3,5),(1,3,6),(1,4,5),(2,3,5)]
However, I want smallTriplets to print the sum with some customization. To be more specific, it will be better if I could replace let sum = x + y + z in smallTriplets with some code so that it gives output like:
Sum is 1+3+5 = 9
Sum is 1+3+6 = 10
Sum is 1+4+5 = 10
Sum is 2+3+5 = 10
I am expecting that code to have a string like "Sum is " ++ show(x) ++ "+" ++ show(y) ++ "+" ++ show(z) ++ " = " ++ show(x + y + z) ++ "\n"
How can I do that?
If this is not possible then please show me how to print:
Sum is 1+3+5 = 9
Sum is 1+3+6 = 10
Sum is 1+4+5 = 10
Sum is 2+3+5 = 10
What's the problem of writing "Sum is " ++ show x ++ "+" ++ show y ++ "+" ++ show z ++ " = " ++ show sum instead of (x, y, z)?
You could like this
main = do
let helper x y z s = "Sum is " ++ show x ++ "+" ++ show y ++ "+" ++ show z ++ " = " ++ show s
let smallTriplets xs ys zs = [ helper x y z sum | x <- xs, y <- ys, z <- zs, let sum = x + y + z, sum <= 10]
putStr $ unlines $ smallTriplets [1,2] [3,4] [5,6]
Here, smallTriplets returns a [String] instead of a [(,,)]; unlines converts the [String] to a String with embedded \ns; finally, putStr prints the string.
This is a quick and dirty solution which alters the function smallTriplets, so if you planned to use the original result in other ways this solution will not help.
If your aim is to log things you do, then a more complex solution is needed. Maybe using the writer monad?

How do I create a recursive infix parser that does not hang?

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.

Accessing a list entry and showing its values

I have a function
(.#.) :: [a] -> Integer -> a -- 1-indexing with 'Integer'
xs .#. j = xs !! (fromIntegral $ j-1)
showIntegers :: [Integer] -> String
showIntegers r = let
str = concat $ "List: " : [r (.#.) j | j <- [1..length r]]
How can I show r (.#.) j as a Char/String rather than an integer? I tried using show, but it gave me an error.
Here is an example of how I used show:
str = concat $ "List: " : [show $ r (.#.) j | j <- [1..length r]]
Example input and output:
> showIntegers [1,2,3]
List: 1 2 3
You should just use Data.List.intercalate or even better use unwords.
import Data.List
showIntegers :: [Integer] -> String
showIntegers r = "List: " ++ intercalate " " $ map show r
--showIntegers r = "List: " ++ unwords $ map show r
EDIT: In either case you should avoid using !! especially to enumerate the original list.
First I would get rid of .#. it is just going to confuse you to use a different numbering system, best to rip that bandaid off.
Next realize that [show $ r !! j <- 0 .. length r - 1] is the same as map show r (and the latter is standard).
Now going with that you have: concat $ "List: " : (map show r) which creates List: 123 because we lost the spaces.
We could reproduce the spaces but what is the difference between using intercalate and concat? Honestly the best solution without using intercalate would be to reproduce intercalate (whose source code is available on Hackage).
Just remove the parenthesis around (.#.) and it works.
If you have an infix operator !#$ , with something before and after it, e.g. x !#$ y, you must not use parentheses. In the other cases, add parentheses, like in the type declaration.
(this technically answers the question, but Guvante's advice is better.)

Is there a better way of doing this in Haskell?

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 =.

Haskell non-exhaustive patterns and converting function output

I have a function that wants to list all of a dataType.
fn [] = []
fn (dt#(DataType t d y [(f,r)]):dts) = ["T:" ++ t ++ " D: " ++ d ++ " R: " ++ show y ++ "Ra" ++ show (fnAvg dt)] ++ fn dts
Where t and d are strings, y is an int, f is a string and r is an int (not sure f and r matter though, will explain furthur on).
I got the error non-exhaustive patterns, and presumed it was because I didn't have one for when there was only one element in the list, so I added this between the other patterns:
fn [dt#(DataType t d y [(f,r)])] = ["T:" ++ t ++ " D: " ++ d ++ " R: " ++ show y ++ "Ra" ++ show (fnAvg dt)]
It compiled, but when I called the function it once again told me 'non-exhaustive patterns'. I'm struggling to think of what pattern i've missed, should I add a wildcard pattern afterward to catch everything? I'm not looking for someone to type out the answer, but hints or suggestions are welcome.
The pattern [(f,r)] only matches when the list contains one element. If it contains zero, or two, or any other number, you have a pattern match failure.
What the code should do in this instance, I couldn't say...
You do already cover the one-element-list case: that matches fn (dt#(DataType t d y [(f,r)]):[]), since dts can be anything including the empty list.
Indeed there's no reason to use explicit recursion here: you basically have something like
f [] = []
f (x:xs) = g x ++ f xs
Compare that to the monad instance of lists:
instance Monad [] where
return x = [x]
[] >>= _ = []
(x:xs) >>= g = g x ++ (xs >>= g)
So you should write you function as
fn l = l >>= \dt#( DataType t d y [(f,r)] )
-> ["T:" ++ t ++ " D: " ++ d ++ " R: " ++ show y ++ "Ra" ++ show (fnAvg dt)]
That won't fix your problem though, but it makes it obvious what's going on: evidently, DataType t d y [(f,r)] is not the only valid pattern for that type. As MathematicalOrchid points out, [(f,r)] matches only a list with length 1, but you need to cover other lengths as well.
fn l = l >>= \dt -> case dt of
DataType t d y [(f,r)]
-> ["T:" ++ t ++ " D: " ++ d ++ " R: " ++ show y ++ "Ra" ++ show (fnAvg dt)]
DataType t d y []
-> ["Some other stuff"]
DataType t d y [(f,r), ...]
-> ["Yet other stuff"]
or whatever.
Indeed, if you only ever return [ ("stuff") ] here, then you're not really using the monadic bind functionality at all: you could have written the recursive version without ++, only reconstruct the thing with :, and in fact you have simply a map operation:
fn = map $ \dt -> case dt of
DataType t d y [(f,r)]
-> "T:" ++ t ++ " D: " ++ d ++ " R: " ++ show y ++ "Ra" ++ show (fnAvg dt)
DataType t d y []
-> "Some other stuff"
DataType t d y [(f,r), ...]
-> "Yet other stuff"

Resources