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?
Related
In the following code, line 4, I have an expression sandwiched between two IO actions in a do block:
1 doubleX :: (Show x, Num x) => x -> IO ()
2 doubleX x = do
3 putStrLn ("I will now double " ++ (show x))
4 let double = x * 2
5 putStrLn ("The result is " ++ (show double))
I understand do notation as chaining monadic operations together using >>= or >>. But how does that work when you have an expression in between? You couldn't just glue lines 3-5 together using >>.
I'm going to crib from my very similar answer here (though probably not a duplicate since that question doesn't explicitly deal with let).
The Report gives a full translation from do syntax into kernel Haskell; the parts relevant to your question are:
do {e} = e
do {e;stmts} = e >> do {stmts}
do {let decls; stmts} = let decls in do {stmts}
So your code desugars like this:
doubleX x = do
putStrLn ("I will now double " ++ (show x))
let double = x * 2
putStrLn ("The result is " ++ (show double))
==> do {e;stmts} rule
doubleX x =
putStrLn ("I will now double " ++ (show x)) >> do
let double = x * 2
putStrLn ("The result is " ++ (show double))
==> do {let decls; stmts} rule
doubleX x =
putStrLn ("I will now double " ++ (show x)) >>
let double = x * 2 in do
putStrLn ("The result is " ++ (show double))
==> do {e} rule
doubleX x =
putStrLn ("I will now double " ++ (show x)) >>
let double = x * 2 in
putStrLn ("The result is " ++ (show double))
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 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"
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)]
I'm looking for a function (let's name it diamond) that "draws" a diamond-shaped "object" by defining only the length of it's diagonal (e.g.: as shown below, so the length of the diagonal in this case is 5 "*" but only 3 are visible):
Main> diamond 5
Output:
*
***
*****
***
*
I have these functions:
stars x
| (x mod 2 == 1) = (firstHalf x) ++ [x] ++ reverse(firstHalf x)
| otherwise = (firstHalf x) ++ reverse(firstHalf x)`
firstHalf x = take (x div 2) (iterate (2+) 1)
space x = map (div 2) (map ((x+1)-) (stars x))
Example output:
space 5 = [2,1,0,1,2]
stars 5 = [1,3,5,3,1]
This function might work but I don't know how to fix this error:
Type error in application:
Expression : replicate (stars x) ['*']
Term : stars x
Type : [Int]
Does not match : Int
diamond x = mapM_ putStrLn $ (replicate (space x) [' ']) ++ (replicate (star x) ['*'])
And I guess even if this error was fixed it would still need a tweak that would join those two lists to get the desired result. Any ideas?
You can generate a number of stars with replicate:
ghci> replicate 5 '*'
"*****"
You can also do this with any other character, such as a space (' ').
You can print a line to the screen with putStrLn:
ghci> putStrLn (replicate 5 '*')
*****
Here is a program that generates the star above:
main = do
putStrLn $ replicate 2 ' ' ++ replicate 1 '*'
putStrLn $ replicate 1 ' ' ++ replicate 3 '*'
putStrLn $ replicate 0 ' ' ++ replicate 5 '*'
putStrLn $ replicate 1 ' ' ++ replicate 3 '*'
putStrLn $ replicate 2 ' ' ++ replicate 1 '*'
You can define functions with =:
hello x = putStrLn $ "Hello " ++ x
main = do
hello "Bob" -- prints "Hello Bob"
(If you do this from the ghci prompt, you have to say let first: eg. let hello x = putStrLn $ "Hello " ++ x)
I don't know why I spent so much time on this question, but I felt like it. Typically we want questions to provide some evidence that you have spent some time trying to solve the problem before asking for help. Merry Christmas...
I have given you all the pieces. Now you have to put them together.