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
Related
Write a program that reads a text in an endless loop, every single word
flipped over and then put back together as text. If the input is empty, the program should
abort, stop.
To do this, write a reverseWords::String -> String function that does the reversing
is working.
for example:
reverseWords "Hello World, 123" -> "olleH ,dlroW 321"
my code
reverseWords :: String -> String
reverseWords = unwords . reverse . words
doesnt work
The function reverse reverses the entire list, so you are getting the words in the reverse order. What you want instead, is to reverse each element separately, which can be fixed with map:
reverseWords = unwords . map reverse . words
If you need to preserve spacing characters other than ' ', then things get a little tricky. Fortunately, the split package can help.
import Data.List.Split
import Data.Char
reverseWords :: String -> String
reverseWords = concatMap reverse . split (whenElt isSpace)
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 "\\" []
\
I want to read an input like 12 34 56 into three integers using Haskell.
For a single integer, one might use myInteger <- readLn. But for this case, I have not found any solution, except the one of first reading a line, then replacing all spaces with ,, (using something like:
spaceToCommas str =
let repl ' ' = ','
repl c = c
in map repl str
) and then calling read '[' ++ str ++ ']' which feels very hackish. Also, it does not allow me to state that I want to read three integers, it will attempt to read any amount of integers from stdin.
There has to be a better way.
Note that I would like a solution that does not rely on external packages. Using e.g. Parsec is of course great, but this simple example should not require the use of a full-fledged Parser Combinator framework, right?
What about converting the string like:
convert :: Read a => String -> [a]
convert = map read . words
words splits the given string into a list of strings (the "words") and then we perform a read on every element using map.
and for instance use it like:
main = do
line <- getLine
let [a,b,c] = convert line :: [Int] in putStrLn (show (c,a,b))
or if you for instance want to read the first three elements and don't care about the rest (yes this apparently requires super-creativity skills):
main = do
line <- getLine
let (a:b:c:_) = convert line :: [Int] in putStrLn (show (c,a,b))
I here returned a tuple that is rotated one place to the right to show parsing is done.
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 ++ ">"
How do I get a search match from a list of strings in Haskell?
module Main
where
import List
import IO
import Monad
getLines = liftM lines . readFile
main = do
putStrLn "Please enter your name: "
name <- getLine
list <- getLines "list.txt"
-- mapM_ putStrLn list -- this part is to list out the input of lists
The first thing to do, the all-important first principle, is to get as much of the thinking out of main or out of IO as possible. main should where possible contain all the IO and maybe nothing but IO decorated with pure terms you define elsewhere in the module. Your getLines is mixing them unnecessarily.
So, to get that out of the way, we should have a main that is something like
main =
do putStrLn "What is your name?"
name <- getContents
names <- readFile "names.txt"
putStrLn (frankJ name names)
-- or maybe the more austere segregation of IO from all else that we get from:
main =
do putStrLn greeting
name <- getContents
names <- readFile nameFile
putStrLn (frankJ name names)
together with the 'pure' terms:
greeting, nameFile :: String
greeting = "What is your name?"
nameFile = "names.txt"
Either way, we are now really in Haskell-land: the problem is now to figure out what the pure function:
frankJ :: String -> String -> String
should be.
We might start with a simple matching function: we get a match when the first string appears on a list of strings:
match :: String -> [String] -> Bool
match name namelist = name `elem` namelist
-- pretty clever, that!
or we might want to normalize a bit, so that white space at the beginning and end of the name we are given and the names on the list doesn't affect the match. Here's a rather shabby way to do that:
clean :: String -> String
clean = reverse . omitSpaces . reverse . omitSpaces
where omitSpaces = dropWhile (== ' ')
Then we can improve on our old match, i.e. elem:
matchClean :: String -> [String] -> Bool
matchClean name namelist = match (clean name) (map clean namelist)
Now we need to follow the types, figuring out how to fit the type of, say, matchClean:: String -> [String] -> Bool with that of frankJ :: String -> String -> String. We want to fit it inside our definition of frankJ.
Thus, to 'provide input' for matchClean, we need a function to take us from a long string with newlines to the list of stings (the names) that matchClean needs: that's the Prelude function lines.
But we also need to decide what to do with the Bool that matchClean yields as value; frankJ, as we have it, returns a String. Let us continue with simple-minded decomposition of the problem:
response :: Bool -> String
response False = "We're sorry, your name does not appear on the list, please leave."
response True = "Hey, you're on the A-list, welcome!"
Now we have materials we can compose into a reasonable candidate for the function frankJ :: String -> String -> String that we are feeding into our IO machine defined in main:
frankJ name nametext = response (matchClean name (lines nametext))
-- or maybe the fancier:
-- frankJ name = response . matchClean name . lines
-- given a name, this
-- - pipes the nametext through the lines function, splitting it,
-- - decides whether the given name matches, and then
-- - calculates the 'response' string
So here, almost everything is a matter of pure functions, and it is easy to see how to emend things for further refinement. For example, maybe the name entered and the lines of the text file should be further normalized. Internals spaces should be restricted to one space, before the comparison. Or maybe there is a comma in lines on the list since people are listed as "lastname, firstname", etc. etc. Or maybe we want the response function to use the person's name:
personalResponse :: String -> Bool -> String
personalResponse name False = name ++ " is a loser, as far as I can tell, get out!"
personalResponse name True = "Ah, our old friend " ++ name ++ "! Welcome!"
together with
frankJpersonal name = personalResponse name . matchClean name . lines
Of course there are a million ways of going about this. For example, there are regex libraries. The excellent and simple Data.List.Split from Hackage might also be of use, but I'm not sure it can be used by Hugs, which you might be using.
I note that you are using old-fashioned names for the imported modules. What I have written uses only the Prelude so imports are unnecessary, but the other modules are now called "System.IO", "Data.List" and "Control.Monad" in accordance with the hierarhical naming system. I wonder if you are using an old tutorial or manual. Maybe the pleasant 'Learn You a Haskell' site would be better? He affirms he's using ghc but I think that won't affect much.
If you wan't a list of all lines in your list.txt that contain the name,
you can simply use
filter (isInfixOf name) list
but I'm not sure if I understood your question correct.