Reputation: 688
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.
Upvotes: 3
Views: 6602
Reputation: 12060
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 String
s 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!
Upvotes: 5
Reputation: 789
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
...
Upvotes: 3