ガードの繰り返しを避ける
まず、書き直すことができます
function input
| this && that && third thing && something else = ... -- you only actually needed brackets for (head xs)
| this && that && third thing && something different = ....
| this && that && a change && ...
...
| notthis && ....
と
function input | this = function2 input'
| notthis = function4 input'
function2 input | that = function3 input''
| notthat = ...
これにより、200 行のコードが簡素化されるはずcopoですが、それでもまだ間違ったアプローチです。
関数を使用して、同じ問題を毎回ではなく 1 回だけ処理する
何度も処理する操作を処理するための 4 つのケースは、おそらく次のような 1 つの関数に置き換えることができます。
operation :: Num a => Char -> a -> a -> a
operation x = case x of
'+' -> (+)
'-' -> (-)
'*' -> (*)
'/' -> (/)
_ -> error ("operation: expected an operation (+-*/) but got " ++ [c])
文字を 1 つずつテストする代わりにリスト関数を使用する
いくつかの標準関数を使用して、すべての単一文字チェックを減らして、存在する数だけを取得する必要があります。takeWhile :: (a -> Bool) -> [a] -> [a]、 それで
takeWhile isDigit "354*243" = "354"
takeWhile isDigit "+245" = ""
対応するものがありdropWhileます:
dropWhile isDigit "354*1111" = "*1111"
dropWhile isDigit "*1111" = "*1111"
したがって、コードの最も劇的な短縮は、copo を開始することです。
copo xs = let
numText = takeWhile isDigit xs
theRest = droWhile isDigit xs
num = read numText
....
in answer....
ただし、 と の両方が必要な場合は、 と呼ばれるショートカットがありtakeWhileますdropWhile。spanspan p xs == (takeWhile p xs, dropWhile p xs)
copo xs = let
(numText,theRest) = span isDigit xs
num = read numText
....
in answer....
コードを繰り返す代わりに再帰を使用する
234あなたはそれ234*56から対処し234*56/23ます....
これを への再帰呼び出しに置き換えるcopoか、ツリーを作成することができます。これは、通常の演算子の優先順位 (+ または - の前に * または /) に従うかどうかによって異なります。