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 =.
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
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
@ user2407038 Ihr 'putStrLn' wird einige Zeilenumbrüche verpassen;) – Carsten