I wrote this code:
toCouplesFile = do inputFile <- openFile "deletedId.csv" ReadMode
outputFile <- openFile "couples.txt" WriteMode
readAndChange inputFile outputFile
readAndChange i o = do iseof <- hIsEOF i
if iseof then (return o)
else do line <- hGetLine i
hPutStrLn o (show (extractNameAndId line))
readAndChange i o
I wonder if I can rewrite this code using just one function, using something similar to this pattern:
function x = do ...
label
.....
if ... then label else exit
You’re making life difficult by programming in a needlessly imperative way. You’re programming in the beautiful Haskell language and you’re looking for a
gotoconstruct!Why not just
import Control.Applicative (<$>)and write(Yup, that’s almost a one-liner. It’s in clean, functional style and uncluttered by the mechanics of reading and writing lines. As much as possible of the processing is done in pure code, only input and output are IO-based.)
Explanation:
Here
unlines.map (show.extractNameAndId).linesprocesses your input by chopping it into lines, applyingextractNameAndIdthenshowto each one usingmap, then joining them back together again withunlines.unlines.map (show.extractNameAndId).lines <$> readFile "deletedId.csv"will read the file and apply the processing function.<$>is pleasant syntax forfmap.writeFile "couples.txt" =<< getansweris the same asgetanswer >>= writeFile "couples.txt"– get the answer as above then write it to the file.Try writing
greet xs = "hello " ++ xsthen in ghci do these for funthe final one is how we used
<$>inreadAndChange. If there’s a lot of data indeletedId.csv you’ll miss the hello, but of course you can do
to see the first 4 lines.
So
$lets you use your function on the arguments you gave it.greet :: String -> Stringso if you writegreet $ person, thepersonhas to be of typeString, whereas if you writegreet <$> someone, thesomeonecan be anything that produces aString– a list of Strings, anIO String, aMaybe String. Technically,someone :: Applicative f => f String, but you should read up on type classes and Applicative Functors first. Learn You a Haskell for Great Good is an excellent resource.For even more fun, if you have a function with more than one argument, you can still use the lovely Applicative style.
Try
Here you use
<$>after the function and<*>between the arguments it needs. How it works is a little mind-blowing at first, but it’s the most functional style of writing effectful computations.Next read up about Applicative Functors. They’re great.
http://learnyouahaskell.com/functors-applicative-functors-and-monoids
http://en.wikibooks.org/wiki/Haskell/Applicative_Functors