0

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

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

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

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

4

2 回答 2

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 开始

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,或生成一棵树。这取决于您是否应该遵守正常的运算符优先级(* 或 / 在 + 或 - 之前)。

于 2013-04-06T13:00:26.880 回答
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 = ...
于 2013-04-06T16:08:12.907 回答