Moving To New Line In Haskell - Updated - haskell

I have the following functions in Haskell that must print the sales of weeks. Each sale in a new line. But it is not working the way i expect it to. The problem i have is the newline character '\n'.
Code:
printWeeks :: Int->String
printWeeks 0 = printWeek 0
printWeeks x = printWeeks(x-1) ++ printWeek x
printWeek :: Int->String
printWeek x = show(x) ++ " " ++ stars (sales x) ++ "'\n'"
I have tried many ways but the new line character is not working as expected. Everything is printed on the same line whichis not what i want.
Need help?
thanks
UPDATE
The following is not working because of compile errors. The errors comes from the second line of formatLines. The type decalaration is causing errors. Need help here
formatLine :: (Name,Price)->IO()
formatLine (a,b) = putStrLn (a ++ dots ++ p)
where
x=(length a)
p=(formatPence b)
y=length p
z=lineLength-(x+y)
dots = printDots z
formatLines :: [(Name,Price)]->IO()
formatLines []= ""
formatLines (a:x) = formatLines x ++ formatLine a

You should use ++ "\n" to append a newline to the output; your current code will add a ', then a newline, then another '.
As #marcog points out, be sure to use putStr to print it out (or don't append the newline at all and use putStrLn). Example:
Hugs> putStr (show 4 ++ "\n")
4
Hugs> putStrLn (show 4 ++ "\n")
4
Hugs> print (show 4 ++ "\n")
"4\n"
(Note that the Hugs interpreter adds extra newlines after each output.)

You are probably printing the string using print x, which is equivalent to putStrLn (show x). show x is converting the newlines into readable characters \ and n. You need to use putStrLn x instead, or putStr x if you don't want to append a newline to the end of the string.
You should also remove the single quotes you have around the newline, unless that was intentional.

It's a bit of a riddle why so much action is happening under the heading of IO. This is maybe a little verbose. I couldn't tell where lineLength was coming from so I made it a parameter.
formatLine :: Int -> (Name,Price) -> String
formatLine linelength (name, price) = name ++ dotfill ++ showprice
where
showprice :: String
showprice = formatPence price
extra :: Int
extra = linelength - length (name ++ showprice)
dotfill :: String
dotfill = replicate extra '.'
formatLines :: Int -> [(Name, Price)] -> String
formatLines linelength []= ""
formatLines linelength (first:rest) =
(formatLine linelength first ++ "\n") ++ formatLines linelength rest
standardPrint :: [(Name, Price)] -> IO ()
standardPrint listing = putStrLn (formatLines 50 listing)
fileAwayPrices :: FilePath -> [(Name,Price)] -> IO()
fileAwayPrices filename listing = writeFile filename (formatLines 70 listing)
testlist :: [(Name,Price)]
testlist = [("oats",344),("barley", 299),("quinoa",599)]
-- *Main> standardPrint testlist
-- oats...........................................344
-- barley.........................................299
-- quinoa.........................................599
type Name = String
type Price = Integer
formatPence n = show n

Re your update: your type declaration is correct, it's the rest of formatLines that's wrong.
formatLines :: [(Name,Price)]->IO()
formatLines [] = return ()
formatLines (a:x) = formatLines x >> formatLine a
A more concise way of writing that is
formatLines :: [(Name,Price)]->IO()
formatLines = mapM_ formatLine . reverse

Related

How can I break line on Haskell?

I tried break line using \n, putStrLn and print but nothing works.
When I use \n the result only concatenates the strings, and when I use putStrLn or print I receive a type error.
Output for \n:
formatLines [("a",12),("b",13),("c",14)]
"a...............12\nb...............13\nc...............14\n"
Output for putStrLn:
format.hs:6:22:
Couldn't match type `IO ()' with `[Char]'
Expected type: String
Actual type: IO ()
In the return type of a call of `putStrLn'
In the expression:
putStrLn (formatLine ((fst x), (snd x)) ++ formatLines xs)
In an equation for `formatLines':
formatLines (x : xs)
= putStrLn (formatLine ((fst x), (snd x)) ++ formatLines xs)
Failed, modules loaded: none.
the output for print is the same as that of putStrLn
Here is my code:
formatLine :: (String,Integer) -> String
formatLine (s, i) = s ++ "..............." ++ show i
formatLines::[(String,Integer)] -> String
formatLines [] = ""
formatLines (x:xs) = print (formatLine ((fst x), (snd x)) ++ formatLines xs)
I understand the reason of the error for print and putStrLn but i have no idea how fix it.
Split your code in two parts.
One part simply constructs the string. Use "\n" for newlines.
The second part takes the string and applies putStrLn (NOT print) to it. The newlines will get printed correctly.
Example:
foo :: String -> Int -> String
foo s n = s ++ "\n" ++ show (n*10) ++ "\n" ++ s
bar :: IO ()
bar = putStrLn (foo "abc" 42)
-- or putStr (...) for no trailing newline
baz :: String -> IO ()
baz s = putStrLn (foo s 21)
If you use print instead, you'll print the string representation, with quotes and escapes (like \n) inside it. Use print only for values that have to be converted to string, like numbers.
Also note that you can only do IO (like printing stuff) in functions whose return type is IO (something).
You need to print the results to output.
This is an IO action, and so you cannot have a function signature ending with -> String. Instead, as #chi points out, the return type should be IO (). Further, since you have the function to generate formatted string already, all you need is a function to help you map the printing action over your input list. This you can do using mapM_, like so:
formatLines::[(String,Integer)] -> IO ()
formatLines y = mapM_ (putStrLn . formatLine) y
Demo

how to return one string as multiple lines in IO?

I'm trying to create a show' function that will take a list of tuples and return a string that creates a new line after every tuple. So it would take [(x,y),(a,b),(c,d)] and return
x y
a b
c d
what I have so far in terms of code is
show' :: [(String,Int)] -> String
show' [] = ""
show' (x:xs) = (fst x) ++ " " ++ (show (snd x)) ++ " something that will create a newline in IO " ++ show' xs
Newlines in Haskell can be represented with "\n".
If you are still printing strings to the console that contain the character sequence \n, it probably means you are using print. Use putStr or putStrLn instead.
You don't want to use print because it internally uses show, which encodes the literal newline as the characters \ and n. print is more useful in debugging than in actual production code.
There is function unlines which joins lines and appends newline to each of them. So you can use something like
show' :: [(String, Int)] -> String
show' xs = unlines $ map (\(x,y) -> (show x) ++ " " ++ (show y)) xs
Use putStrLn to print the output otherwise you'll see '\n' instead of newline.

Haskell + output String as type String

I've written a basic recursive function:
bibliography_rec :: [(String, String, Int)] -> String
bibliography_rec [] = ""
bibliography_rec (x:xs) = (citeBook x) ++ "\n" ++ (bibliography_rec xs)
citeBook simply reformats the tuple into a String.
When run with this input:
ghci> bibliography_rec [("Herman Melville", "Moby Dick", 1851),("Georgy Poo", "Alex Janakos", 1666)]
It produces:
"Moby Dick (Herman Melville, 1851)\nAlex Janakos (Georgy Poo, 1666)\n"
I need line by line printing so I used this:
bibliography_rec (x:xs) = putStr ((citeBook x) ++ "\n" ++ (bibliography_rec xs))
My problem is my output NEEDS to be of type String NOT IO ()
I've been stuck on this for way too long so any help is great!
Looks like you're already there, you just need to putStrLn the string instead of printing it (which is what ghci does by default). print runs its argument through show first, so it will quote the escape characters like "\n".
ghci> putStrLn $ bibliography_rec [...]

How to add spaces to string in Haskell

I have a string "AB0123456789" and the output I would like to have is: "AB01 2345 6789" ... I want to add a space after every fourth character. How can I do this?
Main> addSpace "AB0123456789"
"AB01 2345 6789"
With Data.List.intercalate and Data.List.Split.chunksOf this is easy:
import Data.List.Split
addSpace :: String -> String
addSpace = intercalate " " . chunksOf 4
This may not be the most efficient:
addSpace xs = if length xs <= 4
then xs
else take 4 xs ++ " " ++ addSpace (drop 4 xs)
Demo in ghci:
ghci > addSpace "AB0123456789"
"AB01 2345 6789"
I would think pattern matching would make this easiest:
addSpaces :: String -> String
addSpaces xs#(_:_:_:_:[]) = xs
addSpaces (a:b:c:d:xs) = a:b:c:d:' ':addSpaces xs
addSpaces xs = xs
You have to include the first case so you don't potentially get a space at the end, but it's pretty straightforward. This isn't extensible, though, you wouldn't be able to use a function like this to dynamically choose how many characters you want to skip before inserting a space (such as in #cdk's answer)
You can use splitAt. Heres a function that adds space after every nth character.
spaceN :: Int -> String -> String
spaceN n = init . go
where go [] = []
go xs = let (as, bs) = splitAt n xs in as ++ (' ' : go bs)
for your specific case:
λ. spaceN 4 "AB0123456789"
"AB01 2345 6789"
window :: Int -> [a] -> [[a]]
window i = unfoldr (\l -> if null l then Nothing else Just (splitAt i l))
addSpace :: String -> String
addSpace = intercalate " " . window 4

Printing the values inside a tuple in Haskell

I have a list of tuples. For example: [("A",100,1),("B",101,2)]. I need to display it in a simple way. For example: "your name is: A", "Your id is: 100".
If anyone can find a solution for this, it would be a great help. Thanks in advance.
The easiest way to do this is to create a function that works for one of the elements in your list. So you'll need something like:
showDetails :: (String, Int, Int) -> String
showDetails (name, uid, _) = "Your name is:" ++ name ++ " Your ID is: " ++ show uid
Then you would apply this function to each element in the list, which means you want to use the mapping function:
map :: (a -> b) -> [a] -> [b]
So, if your list is called xs, you would want something like:
map showDetails xs
This obviously gives you a result of type [String], so you might be interested in the unlines function:
unlines :: [String] -> String
This simply takes a list of strings, and creates a string where each element is separated by a new line.
Putting this all together, then, gives you:
main :: IO ()
main = putStrLn . unlines . map showDetails $ [("A",100,1),("B",101,2)]
For a single tuple, just pattern match all the elements, and do something with them. Having a function that does that, you can use map to transform the entire list.
import Data.List (foldl')
show_tuple :: (Num a, Num b) => (String, a, b) -> String
show_tuple (name, id, something) =
"Your name is: " ++ name ++ "\n" ++
"Your ID is: " ++ (show id) ++ "\n" ++
"Your something: " ++ (show something) ++ "\n\n"
-- transforms the list, and then concatenates it into a single string
show_tuple_list :: (Num a, Num b) => [(String, a, b)] -> String
show_tuple_list = (foldl' (++) "") . (map show_tuple)
The output:
*Main Data.List> putStr $ show_tuple_list [("ab", 2, 3), ("cd", 4, 5)]
Your name is: ab
Your ID is: 2
Your something: 3
Your name is: cd
Your ID is: 4
Your something: 5
Quick and dirty solution
f (x,y,z) = "your id is " ++ (show y) ++ ", your name is " ++ (show x) ++ "\n"
main = putStrLn $ foldr (++) "" (map f [("A",100,1),("B",101,2)])
OR (by #maksenov)
main = putStrLn $ concatMap f [("A",100,1),("B",101,2)]
Please try:
get1st (a,_,_) = a
get2nd (_,a,_) = a
get3rd (_,_,a) = a
showTuples [] = ""
showTuples (x:xs) = "Your name is:" ++ show(get1st(x)) ++ " Your ID is: " ++ show(get2nd(x)) ++ "\n" ++ showTuples xs
main = do
let x = [("A",100,1),("B",101,2)]
putStrLn . showTuples $ x

Resources