在Haskell中有更好的方法吗?

时间:2014-09-05 04:59:02

标签: haskell integer-arithmetic

我已经写了以下内容来帮助大孩子完成他们的家庭教育工作,并通过学习如何编程来保持思维工作(我认为haskell听起来很棒)。

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? ")

他们是更整洁/更好/更好/更紧凑的方式吗?

1 个答案:

答案 0 :(得分:8)

它将受益于一个关键原则:尽可能将您的纯代码与IO分开。这样可以让您的程序向上扩展并保持main简洁。大let中的大量main不是一种非常实用的方法,并且随着代码的增长而变得更加混乱。

使用类型签名和基本为readLn的{​​{1}}有助于减少一些错误。 (如果您不熟悉fmap read getLine,请访问问题How do functors work in haskell?fmap确实是一个非常灵活的工具。)

fmap

现在处理。如果我用这种数据做更多的事情,或者更频繁地,我会使用记录类型来存储红利,除数,商和余数,所以请记住未来,但这在这里是一种矫枉过正。 / p>

我愚蠢地返回列表而不是元组,因此我可以getInts :: IO (Int, Int) getInts = do putStrLn "Please enter the dividend :" x <- readLn putStrLn " Please enter the divisor :" y <- readLn return (x,y) 使用map全部:

show

拼图的最后一块是输出。我再次喜欢在IO外部生成这个,然后我可以在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 上稍后打印每一行。我更喜欢这个采取记录类型,但我容忍一个字符串列表作为输入,因为我假设我已经mapM_ putStrLn n所有。

show

现在我们可以将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? "] 写为

main

或者更简洁,将函数main = do (x,y) <- getInts let ns = map show ( sums (x,y) ) es = explain ns mapM_ putStrLn es 组合在一起,并使用explain . map show . sums将其应用于getInts的输出:

fmap

您可能会注意到我在证明中添加了main :: IO () main = fmap (explain . map show . sums) getInts >>= mapM_ putStrLn ,使+r始终意味着=,这是正确的数学用法,而镜像的Haskell意味着=。