ガードの繰り返しを避ける
まず、書き直すことができます
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
。span
span 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
か、ツリーを作成することができます。これは、通常の演算子の優先順位 (+ または - の前に * または /) に従うかどうかによって異なります。