如何使用Perl更加懒惰?关于编程习惯的其他各种问题

时间:2013-12-26 07:12:14

标签: perl lazy-evaluation

昨晚,我写了大约200行蹩脚的perl代码,包括意大利面条代码,我无法调试的未定义变量,以及更多内容。最终,我把它放在PerlMonks上并等待。我认为这是最有帮助的回应:

  

超过200行意大利面条代码,输入解析在一个子中的其他所有内容中搅拌。难怪你在调试这只小狗时遇到了麻烦!一些提示可能有助于清理事物:

     
    
        
  • 重构代码,将所有输入解析移出LHCC子,然后将解析后的数据传递给子。这使得您可以编写和调试sub,而无需将输入数据解析为正确的开始。
  •     
  • 请勿使用goto
  •     
  • 不要在if / elsif / else语句中使用空{} - 它们会模糊失败条件
  •     
  • 不要重复代码块 - 使用sub。这包括大量的代码因长而无意义的错误消息而死亡的地方。使用sub并传递要包含在消息中的上下文。这将清理代码并帮助调试逻辑错误。
  •     
  • 不要为不可能发生的事情编码(n%2只能是0或1)以避免混乱代码并模糊逻辑
  •     
  • 在“早退出”循环旁边使用。这样可以避免嵌套代码并使其更易于理解。
  •     
  • 使用前检查$ key(和die)。
  •     
  • 为什么我的@StatementsKeys =键%语句;什么时候没有使用@StatementsKeys?
  •     
  
     

我会在适当的时候跟进一个有点版本的代码,但有很多行要删除,这需要一段时间! ;)

这对于Perl代码来说都是非常好的建议。但是我在实施他的建议和真正成为一个懒惰的编码器时遇到了问题。出于一些奇怪的原因,我无法实现他对我编程的所有内容的说法,我非常肯定你是如何学习真正好的编程的。我有2个问题:

首先,您将如何使这个快速脚本优化,更好,代码?我认为在看到这个优化后,我将能够开始使用我的代码更好的方向。顺便说一句,这不是上述消息中提到的代码。

ORIGINAL:

print "
Welcome to the Casio-Maxim Quadrilateral Identification\n
Algorithm. In order to identify said quadrilateral,\n
you must have the coordinates of all 4 vertices.\n
When you are ready to input your coordines, type\n
'ready.' Type 'quit' to exit the CMQIA.\n\n";

my $choice = <STDIN>;
if ($choice =~ /quit/i) {
  if (!&Unit6()) {
    return 0;
  }
}
elsif ($choice =~ /ready/i) {

}
else {
  print "\nCould not interpret, try again\n";
  goto ORIGINAL;
}

print
"\nFor shape ABCD, in which point A has coordinates (X1, Y1), B has coordinates\n\n(X2, Y2), C has coordinates (X3, Y3), and D has coordinates (X4, Y4),\n\nX1 = ";

my $AX = <STDIN>;
chomp $AX;
if ($AX !~ /^-?\d+\.?\d*$/) {
  print "\nMust be numeric value.\n";
  goto ORIGINAL;
}
print "\nY1 = ";

my $AY = <STDIN>;
chomp $AY;
if ($AY !~ /^-?\d+\.?\d*$/) {
  print "\nMust be numeric value.\n";
  goto ORIGINAL;
}
print "\nX2 = ";

my $BX = <STDIN>;
chomp $BX;
if ($BX !~ /^-?\d+\.?\d*$/) {
  print "\nMust be numeric value.\n";
  goto ORIGINAL;
}
print "\nY2 = ";

my $BY = <STDIN>;
chomp $BY;
if ($BY !~ /^-?\d+\.?\d*$/) {
  print "\nMust be numeric value.\n";
  goto ORIGINAL;
}
print "\nX3 = ";

my $CX = <STDIN>;
chomp $CX;
if ($CX !~ /^-?\d+\.?\d*$/) {
  print "\nMust be numeric value.\n";
  goto ORIGINAL;
}
print "\nY3 = ";

my $CY = <STDIN>;
chomp $CY;
if ($CY !~ /^-?\d+\.?\d*$/) {
  print "\nMust be numeric value.\n";
  goto ORIGINAL;
}
print "\nX4 = ";

my $DX = <STDIN>;
chomp $DX;
if ($DX !~ /^-?\d+\.?\d*$/) {
  print "\nMust be numeric value.\n";
  goto ORIGINAL;
}
print "\nY4 = ";

my $DY = <STDIN>;
chomp $DY;
if ($DY !~ /^-?\d+\.?\d*$/) {
  print "\nMust be numeric value.\n";
  goto ORIGINAL;
}

my $SAB = ($BX - $AX)**2 + ($BY - $AY)**2;
my $AB  = sqrt($SAB);
my $SBC = ($CX - $BX)**2 + ($CY - $BY)**2;
my $BC  = sqrt($SBC);
my $SCD = ($DX - $CX)**2 + ($DY - $CY)**2;
my $CD  = sqrt($SCD);
my $SDA = ($AX - $DX)**2 + ($AY - $DY)**2;
my $DA  = sqrt($SDA);
my $SAC = ($CX - $AX)**2 + ($CY - $AY)**2;
my $AC  = sqrt($SAC);
my $SBD = ($DX - $BX)**2 + ($DY - $BY)**2;
my $BD  = sqrt($SBD);

my $MAB = eval { ($BY - $AY) / { $BX - $AX } };
if ($@) {
  print "\nUndefined or No Slope. Sorry, cannot compute.\n";
  goto ORIGINAL;
}

my $MBC = eval { ($CY - $BY) / { $CX - $BX } };
if ($@) {
  print "\nUndefined or No Slope. Sorry, cannot compute.\n";
  goto ORIGINAL;
}

my $MCD = eval { ($DY - $CY) / { $DX - $CX } };
if ($@) {
  print "\nUndefined or No Slope. Sorry, cannot compute.\n";
  goto ORIGINAL;
}

my $MDA = eval { ($AY - $DY) / { $AX - $DX } };
if ($@) {
  print "\nUndefined or No Slope. Sorry, cannot compute.\n";
  goto ORIGINAL;
}

my $MAC = eval { ($CY - $AY) / { $CX - $AX } };
if ($@) {
  print "\nUndefined or No Slope. Sorry, cannot compute.\n";
  goto ORIGINAL;
}

my $MBD = eval { ($DY - $BY) / { $DX - $BX } };
if ($@) {
  print "\nUndefined or No Slope. Sorry, cannot compute.\n";
  goto ORIGINAL;
}

my $ShapeName;
if ($MAB == $MCD) {
  if ($MBC == $MDA) {
    if ((-1 / $MAB) == $MDA && (-1 / $MBC) == $MCD) {
      if ($AB == $BC) {
        $ShapeName = "square";
      }
      else {
        $ShapeName = "rectangle";
      }
    }
    else {
      if ($AB == $BC) {
        $ShapeName = "rhombus";
      }
      else {
        $ShapeName = "parallelogram";
      }
    }
  }
  else {
    if ($BC == $DA) {
      $ShapeName = "isosceles trapezoid";
    }
    else {
      $ShapeName = "trapezoid";
    }
  }
}
else {
  if ($MBC == $MDA) {
    if ($AB == $CD) {
      $ShapeName = "isosceles trapezoid";
    }
    else {
      $ShapeName = "trapezoid";
    }
  }
  else {
    if ((-1 / $MAC) == $MBD) {
      $ShapeName = "kite";
    }
    else {
      $ShapeName = "quadrilateral";
    }
  }
}

print "
Shape ABCD is a $ShapeName.\n
AB = $AB or the square root of ($SAB)\n
BC = $BC or the square root of ($SBC)\n
CD = $CD or the square root of ($SCD)\n
DA = $DA or the square root of ($SDA)\n
AC = $AC or the square root of ($SAC)\n
BD = $BD or the square root of ($SBD)\n
Slope of AB = $MAB\n
Slope of BC = $MBC\n
Slope of CD = $MCD\n
Slope of DA = $MDA\n
Slope of AC = $MAC\n
Slope of BD = $MBD\n";

goto ORIGINAL;

其次,如果我有一位导师来帮助我编码,那么我就不会只是继续发布PerlMonks和Stack Overflow了,但我可以去问我的导师。不幸的是,我已经失去了与我见过的最好的编码人员的联系,他总是帮我解决我的代码问题,我学校里没有人知道谁真的擅长Perl和Python-esque语言。找到我的代码导师的任何建议?

1 个答案:

答案 0 :(得分:4)

首先,您使用标签和gotos来模拟正常的程序流控制语句。

非常极少数情况下,goto语句适用于任何语言。向后跳Perl特别糟糕。在这种情况下,您可以简单地使用:

while (1) {
  ...
  } else {
    print "\nCould not interpret, try again\n";
    continue;
  }
  ...
}

让语言与你合作。

接下来,我希望您宣布自己的变量,是否还确保在文件顶部use strict;,以便声明变量是有用的?

接下来,这部分代码重复了很多,只做了很小的改动:

my $AX = <STDIN>;
chomp $AX;
if ($AX !~ /^-?\d+\.?\d*$/) {
  print "\nMust be numeric value.\n"; goto ORIGINAL;
}

你可以把它变成像这样的子:

sub parse_input {
  my $coord = shift(_@);
  chomp $coord;
  if ($coord !~ /^-?\d+\.?\d*$/) {
    print "\nMust be numeric value.\n";
    return false;
  }
  return true;
}

然后这样称呼它:

my $AX = <STDIN>;
continue unless (parse_input($AX));

my $AY = <STDIN>;
continue unless (parse_input($AY));

my $BX = <STDIN>;
continue unless (parse_input($BX));

my $BY = <STDIN>;
continue unless (parse_input($BY));

my $CX = <STDIN>;
continue unless (parse_input($CX));

my $CY = <STDIN>;
continue unless (parse_input($CY));

my $DX = <STDIN>;
continue unless (parse_input($DX));

my $DY = <STDIN>;
continue unless (parse_input($DY));

接下来,您有许多重复的代码,如下所示:

my $SAB = ($BX-$AX)**2 + ($BY-$AY)**2;
my $AB = sqrt($SAB);

将其分解并使语言适合您。从那里找出错别字也很难,它很密集,难以阅读。

sub pyth {
  my ($AX, $AY, $BX, $BY) = @_;
  return sqrt(($BX-$AX)**2 + ($BY-$AY)**2);
}

并称之为:

my $AB = pyth($AX, $AY, $BX, $BY);
my $BC = pyth($BX, $BY, $CX, $CY);

接下来,您的斜率查找函数使用eval技巧捕获除以零。但是,我们可以直接检查。它更加清晰。

my $MAB = eval{($BY-$AY)/{$BX-$AX}}; if ($@) {print "\nUndefined or No Slope. Sorry, cannot compute.\n"; goto ORIGINAL;}

变为:

if ($BX-$AX == 0) {
  print "\nUndefined or No Slope. Sorry, cannot compute.\n";
  continue;
}

my $MAB = ($BY-$AY)/($BX-$AX);

当然,因为这是你重复一遍的代码的一部分,你应该把它放在一个子目录中。

一个好的经验法则是,如果你必须两次编写代码,它可能会保留,如果你重复了3次或更多次,或者它很长,你应该把它放在一个函数中。

接下来,您将需要处理斜率未定义的情况,因为它们仍然是有效的形状。

最后,加入一些注释,特别是在形状识别代码中,优先级并不是立即明显的,所以你首先要用简单的英语解释逻辑。