Printing a single backslash in haskell using ShowString - haskell

I am trying to return a string including a single backslash in Haskell, I am using showString "\\" []
My function type is Int -> String -> String
however this is outputting two backslashes.
How can I return a string with a single backslash?

showString has type:
showString :: String -> String -> String
so that means you need to provide two strings (you provide one together with an empty string). Basically showString concatenates the two strings (which is not a problem). The function showString "\\" "" returns a string with a single backslash, but it does not print anything (since showString) is a function that only returns content.
Now there is a difference between the content of a string, and its representation. New lines, tabs, unicode characters, etc. are represented by escaping: one uses a backslash followed by some pattern. This pattern is not part of the content of the string.
Nevertheless showString does not print anything. It returns a String, and that string is shown as a string literal by the interactive console.
In order to print the content (not its representation) of a string, you can use putStrLn :: String -> IO () or putStr :: String -> IO () in case you want to omit the new line.
This then produces:
Prelude> putStrLn "\\"
\
PutStrLn will for a given String produce an IO () that will print the string to the standard output channel (stdout). It is somewhat equivalent to print(..) in Python, System.out.println(..) in Java, and Console.WriteLine(..) in C#.

You probably want to use:
putStrLn (showString "\\" [])
Within the GHCi REPL when you enter a value, vs an IO action, is is automatically rendered using show which will then escape some characters.
For example:
Prelude> showString "\\" []
"\\"
Prelude> putStrLn $ showString "\\" []
\

Related

How to deal with "" within strings in haskell

I am currently creating a function in haskell like:
allStrings :: [String] -> String
What i want the function to do is take a list of strings and then split each string with a space character
so say input = ["Today", "Tomorrow"] output = "Today Tomorrow"
One problem i am running into is how to deal with strings that contain "" and char to represent new lines i am not sure how to deal with those i know that quote marks within strings are surrounding by \ what i want to do when we come across quote marks in our string is like so:
input ["Sun\"shine\" ", "Rain"] becomes output -> "Sun""shine" Rain"
is anyone able to help me with how to do this?
Thanks
The best method I'm aware of that joins Strings together in Haskell with a single whitespace is unwords.
Having the following signature:
λ> :t unwords
unwords :: [String] -> String
it perfectly suits your needs.
As for how a string containing a " is displayed (for example the output from unwords, if it contains a " will have a \", that's a printing issue.
If you want the \s to disappear while displaying the string, use putStrLn with the following signature:
λ> :t putStrLn
putStrLn :: String -> IO ()
Like so:
λ> putStrLn $ unwords ["Sun\"shine\" ", "Rain"]
Sun"shine" Rain

how would I get this function to be accepted with putStr in haskell?

how would I get this function to be accepted with putStr in haskell? so it displays each word in a list on a new line??
unlines1 :: [String] -> String
unlines1 [] = []
unlines1 (l:ls) = l ++ (putStr('\n')) : unlines ls
Let me try to be more clear in the larger space provided by an answer.
When you cause GHCi to evaluate a value, e.g.,
> "foo"
GHCi will attempt to show you that value. It does this by determining whether the type of that value is an instance of Show. If it is, GHCi prints the display string that show provides for that value. In the case of strings, show will escape non-printable characters like '\n'. This means that what GHCi actually does is more like:
> putStrLn (show "foo")
This means that
> "foo\nbar"
becomes
> putStrLn (show "foo\nbar")
which, by the definition of show for Strings, becomes
> putStrLn "foo\\nbar"
with the '\n' escaped. This is what GHCi is designed to do. You can't and shouldn't prevent it from doing so.
If, on the other hand, you want to print a String, as in perform the Haskell equivalent of echo or puts or printf, then you must use an IO action to do so. One IO action you can use is putStr :: String -> IO ().
When you evaluate
> putStr "foo"
GHCi will attempt to evaluate the IO () action and display a result. Because it is an IO action, GHCi is designed to execute (perform) the IO for you, in this case printing a string.
So the difference between
> "foo\nbar"
and
> putStr "foo\nbar"
is not that the newline is escaped in one string and unescaped in the other. The newline is always a literal newline. The issue is that the former is showing you the inspectable version of the string (with non-printables escaped) and the latter is actually printing the string.

Haskell interact function

I’m new to Haskell and have a problem with interact function. This is my sample program:
main :: IO ()
main = interact inputLength
inputLength :: String -> String
inputLength input = show $ length input
It compiles but when running doesn’t print the output - just prints the string that is passed to it and moves to the next line. When I pass the interact another String -> String function like this:
upperCase :: String -> String
upperCase input = map toUpper input
it runs ok and prints the argument in uppercase as expected – so what is wrong with the first function?
The String -> String argument given to interact should take a string containing all the input and return a string containing all the output. The reason you see output after pressing enter with interact (map toUpper) is because map toUpper acts lazily -- it can start giving output before all the input is known. Finding the length of a string is not like this -- the whole string must be known before any output can be produced.
You need to either signal an EOF to say that you are done entering input (in the console, this is Control-D on Unix/Mac systems, I believe it's Control-Z on Windows), then it will give you the length. Or you can find the length of each line by saying so:
interact (unlines . map inputLength . lines)
This will always be lazy in each line, so you know you can get one output after each input.
Since acting on lines is such a common pattern, I like to define a little helper function:
eachLine :: (String -> String) -> (String -> String)
eachLine f = unlines . map f . lines
Then you can do:
main = interact (eachLine inputLength)
A more reusable solution:
main = interactLineByLine processLine
-- this wrapper does the boring thing of mapping, unlining etc.... you have to do all the times for user interaction
interactLineByLine:: (String -> String) -> IO ()
interactLineByLine f = interact (unlines . (map processLine) . lines)
-- this function does the actual work line by line, i.e. what is
-- really desired most of the times
processLine:: String -> String
processLine line = "<" ++ line ++ ">"

Finding and replacing words with asterisk, in a text file output

Hello I am new at Haskell and i'm having problems trying to get this script to work. This script reads in arguements from a command line and find them in a seperate text file.
E.G: cat.txt | ./redact house big cat (in compiler)
It redacts certain words in a text file by replacing them with stars (**)asterisks. The number of stars used for each redacted word should equal the number of characters in the word.
module Main where
import System
import Data.Char
import Data.List
lowercase :: String -> String
lowercase = map toLower
main = do
arg1 <- getArgs
txt <- getContents
putStr (redact txt arg1)
redact :: String -> String -> String
redact input xWords = unlines [ work line | line <- lines input ]
where work line = unwords [ foo word | word <- words line ]
foo w | lowercase(w) == lowercase(xWords) = convertWord w 1
| otherwise = w
convertWord Eq a => [a] -> [a]
convertWord = map (const '*')
However, when i try to compile this, GHCi returns the error:
redact.hs:13:38:
Couldn't match expected thye 'Char' with actual type '[Char]'
Expected type: String
Actual type: [String]
In the second argument of 'redact', namely 'arg1'
In the first of 'putStr', namely '<redact txt arg1>'
Failed, module loaded: none.
So the code:
putStr (redact txt arg1)
is causing the problem.
Thank you in advance for any help and if you can improve the code in anyway that would be great.
EDIT:
I want to enter as many args as possible, it doesnt matter how many args you enter, i tried:
(arg1:arg2:arg3:arg4:arg5:_) <- getArgs
but I have to enter EXACT 5 args, It shouldn't matter how many args I enter.
I was thinking of using some kind of loop but I am not sure?
Again thank you for your help.
To get it to work with multiple arguments, use getArgs as you have it. The problem lies with
foo w | lowercase(w) == lowercase(xWords) = convertWord w 1
| otherwise = w
where you compare the lowercase of one word to lowercase of multiple words. The latter is not defined, you'd like to compare it to the lowercase of each of the xWords. So first you need to bring them all to lowercase, that's most efficiently done by calling from main redact txt (map lowercase arg1) rather than just redact txt arg1. Then you need to determine if a read word is in the list xWords, that's what the elem function is there for.
foo w | lowercase w `elem` xWords = convertWord w 1
| otherwise = w
BTW, you should maybe not call this function foo even if it's only a local one.
getArgs :: IO [String], so after arg1 <- getArgs, arg1 has the type [String]: it contains all the arguments passed to your program, as a list. But you're using it as String, thus the error: GHC expected arg1 to be a String, but it's a [String].
You can pattern-match on the result like this:
arg1:_ <- getArgs
This results in arg1 containing the first element of the list, and discards the rest of the list. If you don't pass an argument, it'll result in a runtime error. Of course, if you want more specialised behaviour (say, printing an error when no arguments are given), you could use a more complex method of extracting the first argument, such as a case expression.
As far as improvements to your program go:
You can simplify the definition of work using function composition and map rather than the list comprehension: work = unwords . map foo . words (read: "map foo over all the elements of the words, then unwords them").
redact can be simplified similarly, to redact input xWords = unlines . map work . lines $ input.
lowercase(w) is better written as lowercase w.
But your program looks basically fine to me, apart from some oddities (like the missing :: in convertWord's type signature, the additional 1 you pass to it in foo — but going by the somewhat erratic indentation, I guess you edited the code before posting it). I wouldn't make the first two changes unless you understand how they work and are comfortable writing code like that.

Parsec - error "combinator 'many' is applied to a parser that accepts an empty string"

I'm trying to write a parser using Parsec that will parse literate Haskell files, such as the following:
The classic 'Hello, world' program.
\begin{code}
main = putStrLn "Hello, world"
\end{code}
More text.
I've written the following, sort-of-inspired by the examples in RWH:
import Text.ParserCombinators.Parsec
main
= do contents <- readFile "hello.lhs"
let results = parseLiterate contents
print results
data Element
= Text String
| Haskell String
deriving (Show)
parseLiterate :: String -> Either ParseError [Element]
parseLiterate input
= parse literateFile "(unknown)" input
literateFile
= many codeOrProse
codeOrProse
= code <|> prose
code
= do eol
string "\\begin{code}"
eol
content <- many anyChar
eol
string "\\end{code}"
eol
return $ Haskell content
prose
= do content <- many anyChar
return $ Text content
eol
= try (string "\n\r")
<|> try (string "\r\n")
<|> string "\n"
<|> string "\r"
<?> "end of line"
Which I hoped would result in something along the lines of:
[Text "The classic 'Hello, world' program.", Haskell "main = putStrLn \"Hello, world\"", Text "More text."]
(allowing for whitespace etc).
This compiles fine, but when run, I get the error:
*** Exception: Text.ParserCombinators.Parsec.Prim.many: combinator 'many' is applied to a parser that accepts an empty string
Can anyone shed any light on this, and possibly help with a solution please?
As sth pointed out many anyChar is the problem. But not just in prose but also in code. The problem with code is, that content <- many anyChar will consume everything: The newlines and the \end{code} tag.
So, you need to have some way to tell the prose and the code apart. An easy (but maybe too naive) way to do so, is to look for backslashes:
literateFile = many codeOrProse <* eof
code = do string "\\begin{code}"
content <- many $ noneOf "\\"
string "\\end{code}"
return $ Haskell content
prose = do content <- many1 $ noneOf "\\"
return $ Text content
Now, you don't completely have the desired result, because the Haskell part will also contain newlines, but you can filter these out quite easily (given a function filterNewlines you could say `content <- filterNewlines <$> (many $ noneOf "\\")).
Edit
Okay, I think I found a solution (requires the newest Parsec version, because of lookAhead):
import Text.ParserCombinators.Parsec
import Control.Applicative hiding (many, (<|>))
main
= do contents <- readFile "hello.lhs"
let results = parseLiterate contents
print results
data Element
= Text String
| Haskell String
deriving (Show)
parseLiterate :: String -> Either ParseError [Element]
parseLiterate input
= parse literateFile "" input
literateFile
= many codeOrProse
codeOrProse = code <|> prose
code = do string "\\begin{code}\n"
c <- untilP (string "\\end{code}\n")
string "\\end{code}\n"
return $ Haskell c
prose = do t <- untilP $ (string "\\begin{code}\n") <|> (eof >> return "")
return $ Text t
untilP p = do s <- many $ noneOf "\n"
newline
s' <- try (lookAhead p >> return "") <|> untilP p
return $ s ++ s'
untilP p parses a line, then checks if the beginning of the next line can be successfully parsed by p. If so, it returns the empty string, otherwise it goes on. The lookAhead is needed, because otherwise the begin\end-tags would be consumed and code couldn't recognize them.
I guess it could still be made more concise (i.e. not having to repeat string "\\end{code}\n" inside code).
I haven't tested it, but:
many anyChar can match an empty string
Therefore prose can match an empty string
Therefore codeOrProse can match an empty string
Therefore literateFile can loop forever, matching infinitely many empty strings
Changing prose to match many1 characters might fix this problem.
(I'm not very familiar with Parsec, but how will prose know how many characters it should match? It might consume the whole input, never giving the code parser a second chance to look for the start of a new code segment. Alternatively it might only match one character in each call, making the many/many1 in it useless.)
For reference, here's another version I came up with (slightly expanded to handle other cases):
import Text.ParserCombinators.Parsec
main
= do contents <- readFile "test.tex"
let results = parseLiterate contents
print results
data Element
= Text String
| Haskell String
| Section String
deriving (Show)
parseLiterate :: String -> Either ParseError [Element]
parseLiterate input
= parse literateFile "(unknown)" input
literateFile
= do es <- many elements
eof
return es
elements
= try section
<|> try quotedBackslash
<|> try code
<|> prose
code
= do string "\\begin{code}"
c <- anyChar `manyTill` try (string "\\end{code}")
return $ Haskell c
quotedBackslash
= do string "\\\\"
return $ Text "\\\\"
prose
= do t <- many1 (noneOf "\\")
return $ Text t
section
= do string "\\section{"
content <- many1 (noneOf "}")
char '}'
return $ Section content

Resources