我怎么能用小技巧来使用更多的守卫呢?

时间:2013-04-06 10:13:46

标签: haskell guard

当我在ghci中编译我的代码时,没有问题。它可以正确编译。但是,如果我尝试在拥抱中编译它,我会收到错误“编译代码太复杂”。我认为问题是由于许多|条件造成的。

如果我将其更改为使用if / else,则没有问题。我可以添加if / else语句100次,但这将非常烦人和恼人。而不是那样,我试图在20-30 |条件之后放置if / else语句,但如果语句如下所示我无法使|工作:

f x y z     
    | cond1 = e1
    | cond2 = e2
    ...
    if (1)
    then
    | cond30 = e30
    | cond31 = e31
    ...
    else
    | cond61 = e61
    | cond62 = e62

如何以最省力的方式修复代码?完整代码在hpaste上,因为它比StackOverflow的问题大小限制更长。

2 个答案:

答案 0 :(得分:9)

避免重复警卫

首先,你可以重写

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 xs = let 
  numText = takeWhile isDigit xs
  theRest = droWhile isDigit xs 
  num = read numText
  ....
    in answer....

但是如果你想要takeWhiledropWhile这两个名为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来替换它,或者生成一棵树。这取决于你是否应该服从正常的运算符优先级(*或/在+或 - 之前)。

答案 1 :(得分:0)

如果你坚持守卫,而不是

foo a b c d
    | cond1, cond2, cond3 = ...
    | cond1, cond2, cond4 = ...
    | cond5, cond6, cond7 = ...
    | cond5, cond6, cond8 = ...

foo a b c d
    | cond1, cond2 = case () of
        () | cond3 = ...
           | cond4 = ...
    | cond5, cond6 = case () of
        () | cond7 = ...
           | cond8 = ...