2014-09-05 3 views
6

Я написал следующее, чтобы помочь великим детям с их домашней работой по обучению и не забыть работать, изучая, как программировать (я думал, что haskell звучит потрясающе).Есть ли лучший способ сделать это в 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

Я думаю, что все в порядке - вы могли бы сократить некоторые части (например, * merge * 'read' и' getLine' - используя ['<$>'] (http://haddocks.fpcomplete.com/fp/7.4.2/ 20130829-168/base/Data-Functor.html # v: -60--36--62-) и 'div' /' mod', используя ['divMod'] (http://haddocks.fpcomplete.com/fp /7.4.2/20130829-168/base/Prelude.html#v:divMod) - но я думаю, что это нормально для такой простой программы. – Carsten

+0

Стиль в основном предпочтителен, но я бы сделал следующее: 'input <- putStrLn" prompt ">> getLine'; инструкции sequential let не нуждаются в let в каждой строке (т.е. замените все значения let после первого на 3 пробела), вместо того, чтобы иметь' putStrLn' в последовательности, я бы написал строку 'putStrLn $ ' 1 "++" строка 2 "++" строка 3 "' (каждая строка может быть в отдельной строке - если строки выделены, haskell знает свою часть того же оператора). – user2407038

+1

@ user2407038 ваш 'putStrLn' пропустит несколько строк новой строки;) – Carsten

ответ

8

Это выиграет от ключевого принципа: отделите свой чистый код от вашего IO как можно больше. Это позволит вашим программам масштабироваться и поддерживать main breif. Много let в большом main не очень функциональный подход и имеет тенденцию становиться намного более грязным по мере роста вашего кода.

Использование подписи типа и readLn, которое по существу fmap read getLine помогает сократить некоторые трещины. (Если вы не знакомы с fmap, посетить вопрос How do functors work in haskell?. fmap является очень гибким инструментом на самом деле.)

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

Теперь обработку. Если бы я делал больше с такими данными, или чаще, я бы использовал тип записи для хранения дивидендов, делителей, частного и остального, так что имейте это в виду на будущее, но здесь это избыток.

Я hackishly возвращает список, а не кортеж, так что я могу использовать map для show их всех:

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 

Последняя часть головоломки является выходным. Опять же, я предпочитаю генерировать это за пределами IO, а затем я могу только mapM_ putStrLn на нем позже печатать каждую строку. Я бы предпочел, чтобы это взяло тип записи, но я терпеть список строк в качестве ввода вместо этого, так как я предполагаю, что у меня уже есть n все.

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 для зеркала для =.

+0

Спасибо @WillNess, ваши правки всегда хороши и всегда приветствуются. – AndrewC

+1

Спасибо, Андрей, я больше не буду спрашивать. :) :) –

Смежные вопросы