how to write an reversed words function in haskell - string

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)

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 to read line by line from a file in Haskell

im trying to make a programm that should read line by line from a file and check if its a palindrom, if it is, then print.
I'm really new to haskell so the only thing i could do is just print out each line, with this code :
main :: IO()
main = do
filecontent <- readFile "palindrom.txt"
mapM_ putStrLn (lines filecontent)
isPalindrom w = w==reverse w
The thing is, i dont know how to go line by line and check if the line is a palindrom ( note that in my file, each line contains only one word). Thanks for any help.
Here is one suggested approach
main :: IO()
main = do
filecontent <- readFile "palindrom.txt"
putStrLn (unlines $ filter isPalindrome $ lines filecontent)
isPalindrome w = w==reverse w
The part in parens is pure code, it has type String->String. It is generally a good idea to isolate pure code as much as possible, because that code tends to be the easiest to reason about, and often is more easily reusable.
You can think of data as flowing from right to left in that section, broken apart by the ($) operators. First you split the content into separate lines, then filter only the palindromes, finally rebuild the full output as a string. Also, because Haskell is lazy, even though it looks like it is treating the input as a single String in memory, it actually is only pulling the data as needed.
Edited to add extra info....
OK, so the heart of the soln is the pure portion:
unlines $ filter isPalindrome $ lines filecontent
The way that ($) works is by evaluating the function to the right, then using that as the input of the stuff on the left. In this case, filecontent is the full input from the file (a String, including newline chars), and the output is STDOUT (also a full string including newline chars).
Let's follow sample input through this process, "abcba\n1234\nK"
unlines $ filter isPalindrome $ lines "abcba\n1234\nK"
First, lines will break this into an array of lines
unlines $ filter isPalindrome ["abcba", "1234", "K"]
Note that the output of lines is being fed into the input for filter.
So, what does filter do? Notice its type
filter :: (a -> Bool) -> [a] -> [a]
This takes 2 input params, the first is a function (which isPalendrome is), the second a list of items. It will test each item in the list using the function, and its output is the same list input, minus items that the function has chosen to remove (returned False on). In our case, the first and third items are in fact palendromes, the second not. Our expression evaluates as follows
unlines ["abcba", "K"]
Finally, unlines is the opposite of lines.... It will concatinate the items again, inserting newlines in between.
"abcba\nK"
Since STDIO itself is a String, this is ready for outputting.
Note that is it perfectly OK to output a list of Strings using non-pure functions, as follows
forM ["1", "2", "3"] $ \item -> do
putStrLn item
This method however mixes pure and impure code, and is considered slightly less idiomatic Haskell code than the former. You will still see this type of thing a lot though!
Have a look at the filter function. You may not want to put all processing on a single line, but use a let expression. Also, your indentation is off:
main :: IO ()
main = do
filecontent <- readFile "palindrom.txt"
let selected = filter ... filecontent
...

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 ++ ">"

How to read text files into a haskell program?

I have a text file which contains two lists on each line. Each list can contain any number of alphanumeric arguments.
eg [t1,t2,...] [m1,m2,...]
I can read the file into ghc, but how can I read this into another main file and how can the main file recognise each argument separately to then process it?
I think it's best for you to figure out most of this for yourself, but I've got some pointers for you.
Firstly, try not to deal with the file access until you've got the rest of the code working, otherwise you might end up having IO all over the place. Start with some sample data:
sampleData = "[m1,m2,m3][x1,x2,x3,x4]\n[f3,f4,f5][y7,y8,y123]\n[m4,m5,m6][x5,x6,x7,x8]"
You should not mention sampleData anywhere else in your code, but you should use it in ghci for testing.
Once you have a function that does everything you want, eg processLists::String->[(String,String)], you can replcae readFile "data.txt" :: IO String with
readInLists :: FilePath -> IO [(String,String)]
readInLists filename = fmap processLists (readFile filename)
If fmap makes no sense to you, you could read a tutorial I accidentally wrote.
If they really are alphanumeric, you can split them quite easily. Here are some handy functions, with examples.
tail :: [a] -> [a]
tail "(This)" = "This)"
You can use that to throw away something you don't want at the front of your string.
break :: (Char->Bool) -> String -> (String,String)
break (== ' ') "Hello Mum" = ("Hello"," Mum")
So break uses a test to find the first character of the second string, and breaks the string just before it.
Notice that the break character is still there at the front of the next string. span is the same but uses a test for what to have in the first list, so
span :: (Char->Bool) -> String -> (String,String)
span (/= ' ') "Hello Mum" = ("Hello"," Mum")
You can use these functions with things like (==','), or isAlphaNum (you'll have to import Data.Char at the top of your file to use it).
You might want to look at the functions splitWith and splitOn that I have in this answer. They're based on the definitions of split and words from the Prelude.

How do I get a search match from a list of strings in Haskell?

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.

Resources