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

oiy*_*yio 0 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
Run Code Online (Sandbox Code Playgroud)

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

And*_*ewC 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 && ....
Run Code Online (Sandbox Code Playgroud)

function input | this = function2 input'
               | notthis = function4 input'

function2 input | that = function3 input''
                | notthat = ...
Run Code Online (Sandbox Code Playgroud)

这应该简化你的200行copo代码,但它仍然是错误的方法.

使用函数只处理一次相同的问题,而不是每次都处理

处理您经常处理的操作的4个案例可以用一个函数替换,可能如下:

operation :: Num a => Char -> a -> a -> a
operation x = case x of
   '+' -> (+)
   '-' -> (-)
   '*' -> (*)
   '/' -> (/)
   _   -> error ("operation: expected an operation (+-*/) but got " ++ [c])
Run Code Online (Sandbox Code Playgroud)

使用列表函数而不是一次测试一个字符

您应该使用一些标准函数来帮助减少所有单个字符检查,只需抓取尽可能多的数字.takeWhile :: (a -> Bool) -> [a] -> [a]所以

takeWhile isDigit "354*243" = "354"
takeWhile isDigit "+245" = ""
Run Code Online (Sandbox Code Playgroud)

并且有相应的dropWhile:

dropWhile isDigit "354*1111" = "*1111"
dropWhile isDigit "*1111" = "*1111"
Run Code Online (Sandbox Code Playgroud)

所以最明显的缩短代码就是开始代码

copo xs = let 
  numText = takeWhile isDigit xs
  theRest = droWhile isDigit xs 
  num = read numText
  ....
    in answer....
Run Code Online (Sandbox Code Playgroud)

但有一个快捷键,如果你想既takeWhiledropWhile,叫span,因为span p xs == (takeWhile p xs, dropWhile p xs)

copo xs = let 
  (numText,theRest) = span isDigit xs
  num = read numText
  ....
    in answer....
Run Code Online (Sandbox Code Playgroud)

使用递归而不是重复代码

你处理234,然后234*56234*56/23然后....

您可以使用递归调用替换它copo,或生成树.这取决于您是否应该遵守正常的运算符优先级(*或/在+或 - 之前).