我已经写了以下内容来帮助大孩子完成他们的家庭教育工作,并通过学习如何编程来保持思维工作(我认为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? ")
他们是更整洁/更好/更好/更紧凑的方式吗?
答案 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意味着=。