Is there a better way to do this in Haskell?

I wrote the following to help great children with their homework learning and not to forget to work learning how to program (I thought haskell sounds amazing).

main :: IO () main = do putStrLn "Please enter the dividend :" inputx <- getLine putStrLn "Please enter the divisor :" inputy <- getLine let x = (read inputx) :: Int let y = (read inputy) :: Int let z = x `div` y let remain = x `mod` y putStrLn ( "Result: " ++ show x ++ " / " ++ show y ++ " = " ++ show z ++ " remainder " ++ show remain ) putStrLn ( "Proof: (" ++ show y ++ " x " ++ show z ++ ") = " ++ show (y * z) ++ " + " ++ show remain ++ " = " ++ show ((y * z) + remain)) putStrLn ( "Is this what you had? ") 

Is their a neater / nicer / better / more compact way to do this?

+6
source share
1 answer

This will benefit from a key principle: separate your clean code from your IO as much as possible. This will increase your programs and save the main breif. A lot of let in a large main not a very functional approach and tends to become much more messy as your code grows.

Using a type signature and readLn , which essentially fmap read getLine helps reduce some cracks. (If you are new to fmap , visit the question How do functors work in haskell?. fmap really a very flexible tool.)

 getInts :: IO (Int, Int) getInts = do putStrLn "Please enter the dividend :" x <- readLn putStrLn " Please enter the divisor :" y <- readLn return (x,y) 

Now processing. If I did more with this data or more often, I would use the record type to store dividends, dividers, private and the rest, so keep this in mind for the future, but here is an excess.

I am hackingly returning a list, not a tuple, so I can use map to show everything:

 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 puzzle is the way out. Again, I prefer to generate this external IO, and then I can just mapM_ putStrLn on it later print each line. I would prefer this to take the record type, but I endure the list of strings as input instead, since I assume that I already have show n everything.

 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 combining explain . map show . sums functions explain . map show . sums explain . map show . sums explain . map show . sums and applying them to the getInts output using fmap :

 main :: IO () main = fmap (explain . map show . sums) getInts >>= mapM_ putStrLn 

You may have noticed that in the proof I added +r to make = always mean = , which is the correct mathematical use, and displays the Haskell value for =.

+8
source

Source: https://habr.com/ru/post/974866/


All Articles