2014-09-05 20 views
6

Ich habe folgendes geschrieben, um den großen Kindern bei ihrer Heimschulungsarbeit zu helfen und meinen Verstand zu halten, indem ich lerne, wie man programmiert (ich fand Haskell großartig).Gibt es einen besseren Weg, dies in Haskell zu tun?

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

Ist ihre neater/nicer/besser/kompaktere Art, dies zu tun?

+0

Ich denke, es ist in Ordnung - Sie könnten einige Teile kürzen (zum Beispiel * merge * 'lesen' und' getLine' - mit ['<$>'] (http://haddocks.fpcomplete.com/fp/7.4.2/) 20130829-168/base/Data-Functor.html # v: -60-36-62-) und 'div' /' mod' mit ['divMod'] (http://haddocks.fpcomplete.com/fp /7.4.2/20130829-168/base/Prelude.html#v:divMod) - aber ich denke, es ist in Ordnung für solch ein einfaches Programm – Carsten

+0

Stil ist meistens eine Vorliebe, aber ich würde folgendes tun: 'input <- putStrLn" prompt ">> getLine'; sequenzielle let-Anweisungen brauchen kein let in jeder Zeile (dh ersetzen alle lets nach dem ersten mit 3 Leerzeichen), anstatt" putStrLn "in Folge zu haben, würde ich' putStrLn $ "schreiben 1 "++" Zeile 2 "++" Zeile 3 "' (jeder String kann in einer eigenen Zeile stehen - solange die folgenden Zeilen eingerückt sind, kennt hakell seinen Teil derselben Anweisung). – user2407038

+1

@ user2407038 Ihr 'putStrLn' wird einige Zeilenumbrüche verpassen;) – Carsten

Antwort

8

Es würde von einem Schlüsselprinzip profitieren: Trennen Sie Ihren reinen Code so weit wie möglich von Ihrem IO. Dies wird Ihre Programme vergrößern und main halten. Viele let in einem großen main ist kein sehr funktioneller Ansatz und neigt dazu, viel unordentlicher zu werden, wenn Ihr Code wächst.

Unter Verwendung einer Typ-Signatur und , die im Wesentlichen fmap read getLine hilft hilft, einige cruft. (Wenn Sie mit fmap nicht vertraut sind, besuchen Sie die Frage How do functors work in haskell?. fmap ein sehr flexibles Werkzeug ist in der Tat.)

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

nun die Verarbeitung. Wenn ich mehr mit dieser Art von Daten oder häufiger machen würde, würde ich einen Datensatztyp verwenden, um die Dividende, den Divisor, den Quotienten und den Rest zu speichern, also denke daran für die Zukunft, aber es ist ein Overkill hier.

ich Rückkehr hackishly eine Liste eher als ein Tupel, so kann ich map zu show sie verwenden alle:

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 

Das letzte Stück des Puzzles ist der Ausgang. Auch hier ziehe ich es vor, dieses externe IO zu generieren und dann kann ich später nur noch mapM_ putStrLn auf jede Zeile drucken. Ich würde es vorziehen, den Aufnahmetyp zu nehmen, aber ich toleriere eine Liste von Zeichenfolgen als Eingabe, da ich annehme, dass ich bereits show n alle habe.

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

Jetzt können wir schreiben main als

main = do (x,y) <- getInts 
      let ns = map show (sums (x,y)) 
       es = explain ns 
      mapM_ putStrLn es 

oder auch kurz und bündig, indem Sie die Funktionen Rohrleitungen zusammen explain . map show . sums, und dass der getInts mit dem Ausgang Anwendung fmap mit:

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

Sie könnten feststellen, dass ich einen +r in den Beweis eingefügt habe, umzu machenbedeutet immer =, was die korrekte mathematische Verwendung ist, und Haskells Bedeutung des Spiegels für =.

+0

Danke @WillNess, deine Änderungen sind immer gut und _always_ willkommen. – AndrewC

+1

Danke, Andrew, ich werde nicht mehr danach fragen. :) :) –

Verwandte Themen