This answer will mostly repeat what is said in the comments (and in your own answer), but with some elaboration that might be useful.
In what follows, I will abuse keyboard input formatting, as in case, when I want to talk about a string as it really is. You may take "as it really is" to mean a certain sequence of bytes in memory or something more Platonic -- feel free to pick your favourite ontology. What matters is that, if I want to refer to case in a Haskell program, I need some way to specify I'm really talking about a string, as Haskell source code is literally a string of characters which is interpreted in a certain manner -- and, in particular, in that interpretation case
would be taken as a keyword introducing a case-statement. The solution adopted by Haskell syntax is using double quotes to introduce string literals, so that "case"
represents case.
That's all well and good, but what about This sentence is not a "sentence"? The problem is that Haskell syntax confiscates, among others, the character ", giving it special meaning, which means "This sentence is not a "sentence""
doesn't actually represent This sentence is not a "sentence" (rather, it represents This sentence is not a applied, like a function, to a variable called sentence
and the empty string -- which is approximately always nonsense). The solution to this problem is confiscating \ in order to use it as an escape character which, when used within a string literal, indicates the following character should be taken literally, and not according to its usual role in Haskell syntax (that is not the only way \ is used as an escape character, but let's not get bogged down in detail). That being so, This sentence is not a "sentence" is represented by "This sentence is not a \"sentence\""
, and all is well in the World.
All of the above probably is, after the long discussion in the comments, very obvious. There are a few interesting things to add, though, about putStrLn
, show
and print
. Starting with putStrLn
, its role can be abstractly described as drawing in your screen something that looks sufficiently like how you would represent a string if you weren't concerned about the mundane constraints of Haskell syntax. There is no fundamental difference between putStrLn
and an hypothetical cartoonifyStrLn
, which would draw a pink Comic Sans string all over your desktop, or even a seeStrLn
, which would plant a visual impression of the string directly in your retina. The point is that putStrLn "This sentence is not a \"sentence\""
represents This sentence is not a "sentence" in a way that is completely external to Haskell. This fact is, fortunately enough, expressed by the type system:
GHCi> -- Actually a string.
GHCi> :t "This sentence is not a \"sentence\""
"This sentence is not a \"sentence\"" :: [Char]
GHCi> -- Note how there won't be any mention of String (or [Char]).
GHCi> :t putStrLn "This sentence is not a \"sentence\""
putStrLn "This sentence is not a \"sentence\"" :: IO ()
Values with IO
in their types stand in for things that are, in part or wholly, external to Haskell. IO
makes it possible to refer to and make use of such things without losing track of this crucial fact about them.
The show
function produces string -- or, more precisely, String
-- representations of Haskell values
GHCi> show 99
"99"
GHCi> show (Just 99)
"Just 99"
That however, is an incomplete description of what show
does. The String
it produces is supposed to represent, as a string literal, a valid representation of the value it is given according to Haskell syntax. That is why show
ing a String
produces a string with extra quotes tacked on...
GHCi> show "case"
"\"case\""
... not to mention all the extra backslashes:
GHCi> show "This sentence is not a \"sentence\""
"\"This sentence is not a \\\"sentence\\\"\""
As for print
, it is just show
followed by putStrLn
, so it tends to do what you expect for most types...
GHCi> print 99
99
GHCi> print (Just 99)
Just 99
... but not for String
s -- in their case, you should just use putStrLn
instead:
GHCi> print "This sentence is not a \"sentence\""
"This sentence is not a \"sentence\""
P.S.: Possibly interesting extra reading about technicalities: How to convert Unicode Escape Sequence to Unicode String in Haskell and Semantics of show w.r.t. escape characters.
P.P.S.: I welcome criticism of my usage of quotation in this answer.