It would benefit from a key principle: separate your pure code from your IO as much as possible. This will let your programs scale up and keep main
breif. Lots of let
in a big main
isn't a very functional approach and tends to get much messier as your code grows.
Using a type signature and readLn
which is essentially fmap read getLine
helps cut down some cruft. (If you're not familiar with fmap
, visit the question How do functors work in haskell?. fmap
is a very flexible tool indeed.)
getInts :: IO (Int, Int)
getInts = do
putStrLn "Please enter the dividend :"
x <- readLn
putStrLn " Please enter the divisor :"
y <- readLn
return (x,y)
Now the processing. If I were doing more with this kind of data, or more frequently, I'd be using a record type to store the dividend, divisor, quotient and remainder, so bear that in mind for the future, but it's an overkill here.
I'm hackishly returning a list rather than a tuple, so I can use map
to show
them all:
sums :: (Int, Int) -> [Int]
sums (x,y) = [x, y, q, r, y * q, y * q + r] where
q = x `div` y
r = x `mod` y
The final piece of the jigsaw is the output. Again I prefer to generate this outside IO and then I can just mapM_ putStrLn
on it later to print each line. I'd prefer this to take the record type, but I'm tolerating a list of strings as input instead since I'm assuming I've already show
n them all.
explain :: [String] -> [String]
explain [x,y,q,r,yq,yq_r] =
[ concat ["Result: ", x, " / ", y, " = ", q, " remainder ", r]
, concat ["Proof: (", y, " x ", q, ") + ", r, " = ", yq, " + ", r, " = ", yq_r]
, "Is this what you had? "]
Now we can write main
as
main = do (x,y) <- getInts
let ns = map show ( sums (x,y) )
es = explain ns
mapM_ putStrLn es
or even more succinctly, by piping together the functions explain . map show . sums
, and applying that to the output of getInts
using fmap
:
main :: IO ()
main = fmap (explain . map show . sums) getInts
>>= mapM_ putStrLn
You might notice that I added a +r
in the proof to make =
always mean =
, which is the correct mathematical usage, and mirror's Haskell's meaning for =.