How can I create a newline inside a String? Is it possible without using IO ()?
formatRow :: Car -> String
formatRow (a, d:ds, c, x:xs) = a ++ " | " ++ x ++ concat xs ++ " | " ++ show c ++ " | " ++ d ++ concat ds ++ (show '\n')
To create a string containing a newline, just write "\n".
If you run your program on Windows, it will automatically be converted to "\r\n".
Note that calling show on it will escape the newline (or any other meta-characters), so don't do foo ++ (show "\n") or foo ++ (show '\n') - just use foo ++ "\n".
Also note that if you just evaluate a string expression in GHCi without using putStr or putStrLn, it will just call show on it, so for example the string "foo\n" will display as "foo\n" in GHCi, but that does not change the fact that it's a string containing a newline and it will print that way, once you output it using putStr.
Related
I need to remove a comma from the last list after writingFile. How to specifically remove the comma from list?
Expected output
[Spa"24""Meta""Outram"1[("Colin",4),("Nixon",6),("Sam",5),("Petrina",7),("Justin",5)],
Spa"25""Zen""Outram"2[("Bryan",7),("Petrina",9),("Colin",4),("Nixon",7),("Sam",5)]]
Output achieved
[Spa"24""Meta""Outram"1[("Colin",4),("Nixon",6),("Sam",5),("Petrina",7),("Justin",5)],
Spa"25""Zen""Outram"2[("Bryan",7),("Petrina",9),("Colin",4),("Nixon",7),("Sam",5)],]
-- turn original spa into String
spaStr :: Spa -> String
spaStr spa#(Spa rid br ar st s)
= "Spa" ++ "\""++ rid ++ "\"" ++ "\"" ++ br ++ "\""++ "\""++ ar ++ "\"" ++ show st ++ show s ++ "," ++"\n"
let newdB = ((addTspa rid br ar (read st))dB)
putStrLn $ spaStr newdB
writeFile "spa.txt" ("[" ++ spaStr newdB ++ "]")
As suggested in the comments, a possible approach is:
Turn your [Spa] to [String] without adding any commas or newlines. This will generate a list like ["aaa", "bbb", "ccc"]
Use intersperse ",\n" on that list to add that separator in the middle of adjacent elements. This will not add the separator to the end. You will get something like ["aaa", ",\n", "bbb", ",\n", "ccc"]
Use concat on the result, obtaining "aaa,\nbbb,\nccc".
Add the final [ and ].
Here is an example which runs and produces your wanted output:
import Data.List (intersperse)
data Spa = Spa String String String Int [(String, Int)]
-- turn original spa into String
spaStr :: Spa -> String
spaStr spa#(Spa rid br ar st s)
= "Spa" ++ "\""++ rid ++ "\"" ++ "\"" ++ br ++ "\""++ "\""++ ar ++ "\"" ++ show st ++ show s
newDb :: [Spa]
newDb =
[ Spa "24" "Meta" "Outram" 1
[("Colin",4),("Nixon",6),("Sam",5),("Petrina",7),("Justin",5)]
, Spa "25" "Zen" "Outram" 2
[("Bryan",7),("Petrina",9),("Colin",4),("Nixon",7),("Sam",5)]
]
main :: IO ()
main =
putStrLn $ "[" ++ concat (intersperse ",\n" $ map spaStr newDb) ++ "]"
Output:
[Spa"24""Meta""Outram"1[("Colin",4),("Nixon",6),("Sam",5),("Petrina",7),("Justin",5)],
Spa"25""Zen""Outram"2[("Bryan",7),("Petrina",9),("Colin",4),("Nixon",7),("Sam",5)]]
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.
I have defined these datatypes which I am trying to create and print now.
type TNonTerminal = String -- will be creating own ones where [A-Z] won't be enough
type TTerminals = Char
type TSymbols = String -- both terminals and nonterminals
data Rule = Rule
{ leftSide :: TNonTerminal
, rightSide :: [TSymbols]
} deriving (Eq)
data RightLinearGrammar = RLG
{ nonterminals :: [TNonTerminal]
, terminals :: [TTerminals]
, firstNonterminal :: TNonTerminal
, rules :: [Rule]
} deriving (Eq)
So I also created those Show instances
instance Show Rule where
show (Rule ls rs) = show ls ++ "->" ++ show rs ++ "\n"
instance Show RightLinearGrammar where
show (RLG n t fn r) = show n ++ "\n" ++ show t ++ "\n" ++ show fn ++ "\n" ++ show r ++ "\n"
And I get this output (for clarification I created the Type RightLinearGrammar and called putStr $ show rlg):
["A","B"] -- [TNonTerminal]
"abc" -- [TTerminals]
"A" -- TNonTerminal
["A"->["aaB"] --
,"A"->["ccB"]
,"B"->["bB"] -- [Rule]
,"B"->["#"]
] --
How should I change the code to get better output like this one?
A,B
a,b,c
A
A->aaB
A->ccB
B->bB
B->#
show is by default going to give you quotes around strings and brackets around lists. If you just go back to concatenating strings and joining lists with commas or newlines, you should get the output you're expecting:
import Data.List (intercalate)
instance Show Rule where
show (Rule ls rs) = ls ++ "->" ++ intercalate "," rs
instance Show RightLinearGrammar where
show (RLG n t fn r) = intercalate "," n ++ "\n" ++ t ++ "\n" ++ fn ++ "\n" ++ (intercalate "\n" $ map show r) ++ "\n"
You either need to replace your type synonyms with newtypes, and define show on them to do what you want, or more likely replace the calls to show in your instances with calls to a custom formatter function.
Note: show is really not the right function for what you're trying to do, since it usually produces output you could paste back into ghci and arguably should be limitted to that use. You could easily define your own function and use it like this:
formatRule :: Rule -> String
formatRule (Rule ls rs) = ls ++ "->" ++ concat (intersperse "," rs) ++ "\n"
formatRightLinearGrammar :: RightLinearGrammar -> String
formatRightLinearGrammar (RLG n t fn r) =
concat (intersperse "," n) ++ "\n"
++ intersperse ',' t ++ "\n"
++ fn ++ "\n"
++ concat (map formatRule r)
Note: this is going to be fairly inefficient for large grammars; you might want to consider re-writing it as
formatRule :: Rule -> String -> String
formatRule (Rule ls rs) = (ls++) . ("->"++) . concatDS (intersperse "," rs) . ("\n"++)
formatRightLinearGrammar :: RightLinearGrammar -> String
formatRightLinearGrammar (RLG n t fn r) =
concatDS (intersperse "," n) $ ("\n"++) $
(intersperse ',' t ++) $ ("\n"++) $
(fn++) $ ("\n"++) $
foldr formatRule "" r
concatDS ss s' = foldr (++) s' ss
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
Like the title says I'm having some trouble printing out symbol codes and their corresponding symbols using Haskell...what I have at the moment is this:
import Data.Char
import Debug.Trace
foo z | trace ("Symbolcode " ++ show z ++ " is " ++ (chr z)) False = undefined
foo z = if (z <= 128)
then foo (z+1)
else show "All done."
...and I get an error like this:
Couldn't match expected type `[Char]' with actual type `Char'
In the return type of a call of `chr'
In the second argument of `(++)', namely `(chr z)'
In the second argument of `(++)', namely `" is " ++ (chr z)'
What am I doing wrong and is there an easier way of doing this (for example without using the trace module)?
You need to convert your Char, as generated by chr z, into a String (For example via [chr z] or return (chr z) or chr z : [] etc). Otherwise, you can't append it to the string before it using ++.
foo z | trace ("Symbolcode " ++ show z ++ " is " ++ [chr z]) False = undefined
It is a bad idea to use trace for anything other than debugging, because the execution order is unreliable.
If you want to do something for all integers in a range, start by making the list [0 .. 127] of integers you want to process. To output some text, you should use an IO action such as putStrLn. Unlike trace, putStrLn will always execute when it is supposed to. Map this IO action over your list to print all the characters.
showCharCode n = putStrLn ("Symbol code " ++ show n ++ " is " ++ [chr n])
foo = mapM_ showCharCode [0 .. 127]