避免重复的守卫
首先,你可以重写
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
代码,但这仍然是错误的方法。
只使用一次函数来处理相同的问题,而不是每次
处理您一次又一次处理的操作的 4 种情况可以用一个函数代替,可能像:
operation :: Num a => Char -> a -> a -> a
operation x = case x of
'+' -> (+)
'-' -> (-)
'*' -> (*)
'/' -> (/)
_ -> error ("operation: expected an operation (+-*/) but got " ++ [c])
使用列表函数而不是一次测试一个字符
您应该使用一些标准函数来帮助减少所有单个字符检查,从而只获取尽可能多的数字。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
,或生成一棵树。这取决于您是否应该遵守正常的运算符优先级(* 或 / 在 + 或 - 之前)。