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 [...]
Related
I'm new to the Haskell. I am finding following task difficult:
Enter a string of characters. Output all palindromes to the file (use the IO monad to work with the file system and input / output, use the list monad to work with the strings).`
Any code is may be helpful. Thank you in advance!
This is what I have tried so far:
palindrome :: Char -> [String]
palindrome n
| n < 0 = []
| even n = map (\front -> front ++ reverse front) fronts
| odd n = map (\front -> front ++ tail (reverse front)) fronts
where ispalindrome :: (Integral a, Show a) => a -> Bool
ispalindrome x = show x = reverse (show x)
main = do
input <- getline
putStrLn print :: IO ()
So this is basically consists of 4 things.
Read Input from the stdin
Convert input string into list of strings
From the above list find out the strings which are palindromes
print these palindromes into file.
If you convert above into functions the signatures of these will be.
String -> [String]
[String] -> [String]
Don't bother about the signature of 1st and 4th for now. These are anyways one line code readily available on internet.
2 is a single function available in Data.List called words.
3 can be again in two parts. A function which find out if a given string is palindrome. Signature will be
String -> Bool
This is also one line code.
Once you have above function the only part remaining is filtering out the strings which are palindromes in given list of strings.
isPalindrome
My haskell is a bit rusty so I don't promise the code below will work %100 yet I tried to stick to the main idea.I hope this answer helps. If you think anything is wrong both logically and syntactically, just write a comment and I will fix it asap.
isPalindrome :: [Char] -> Boolean
isPalindrome w = isPalindrome' w reverse w
where
isPalindrome' :: [Char] -> [Char] -> Boolean
isPalindrome' [] [] = true
isPalindrome' (x:xs) (y:ys) = if x == y then isPalindrome' xs ys else false
isPalindrome' _ _ = false
function above should be fine for checking for palindromes.
for writing to file part, you can create a list of palindromes first, then write all palindromes to a file in another function. so basically, first you split your string into words, then for words in given string you find palindromes, then you write the palindromes into a file.
how to read string from user?
main = do
userInput <- getLine
how to split word with delimiter?
split :: Char -> [Char] -> [[Char]]
split delimiter string = split' delimiter string [] []
where
split' :: Char -> [Char] -> [Char] -> [[Char]] -> [[Char]]
split' delim [] substr splittedStr = splittedStr if substr == [] else reverse substr ++ splittedStr
split' delim (x:xs) substr splittedStr = if x == delim then split' delim xs [] (reverse substr) ++ splittedSubstr else split' delim xs (x ++ substr) splittedSubstr
main idea is you stack characters until you see your delimeter and store them in a list when you see a delimiter.
how to filter palindromes in list?
to filter palindromes in list you use haskell's filter function as
filter isPalindrome (split ' ' userInput)
In the end, you can write a main block to run all of this in right order
main = do
userInput <- getLine
let splittedInput = split ' ' userInput
let palindromes = filter isPalindrome splittedInput
let output = concat (intersperse "\n" palindromes)
writeFile "file.txt" output
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
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.
Been messing around for about 20 minutes now trying to get the new line working however it always shows in GHCI as a single line.
Here is what I enter into GHCi:
displayFilm ("Skyfall",["Daniel Craig", "Judi Dench", "Ralph Fiennes"], 2012, ["Bill", "Olga", "Zoe", "Paula", "Megan", "Sam", "Wally"])
Here is what is printed:
"Skyfall----------\n Cast: Daniel Craig, Judi Dench, Ralph Fiennes\n Year: 2012\n Fans: 7\n"
displayList :: [String] -> String
displayList [] = ""
displayList [x] = x ++ "" ++ displayList []
displayList (x:xs) = x ++ ", " ++ displayList xs
displayFilm :: Film -> String
displayFilm (title, cast, year, fans) =
title ++ "----------" ++
"\n Cast: " ++ (displayList cast) ++
"\n Year: " ++ (show year) ++
"\n Fans: " ++ show (length fans) ++ "\n"
To print a string as it is, without escaping special characters, use:
putStr string
or
putStrLn string
if you want an extra newline at the end. In you case, you are probably looking for
putStr (displayFilm (....))
Why is this needed? In GHCi, if you evaluate an expression s the result will be printed as if running print s (unless it has type IO something -- forget about this special case). If e is a string, print escapes all the special characters and output the result. This is because print is meant to output a string whose syntax follows the one in Haskell expressions. For numbers, this is the usual decimal notation. For strings, we get quotes and escaped characters.
When you type an expression into GHC, it displays it using print. Calling print on a string shows its content but does not evaluate escape sequences:
> print "line1\nline"
"line1\nline2"
Note the quotes.
To display the string as you desire, use putStr or putStrLn (the latter will append a newline).
> putStr "line1\nline2"
line1
line2
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