有用的替代控制结构?

A. *_*Rex 43 loops programming-languages control-structure

有时当我编程时,我发现某些特定的控制结构对我来说非常有用,但在我的编程语言中却无法直接使用.我认为我最常见的愿望是"分裂时"(我不知道该怎么称呼它):

{
    foo();
} split_while( condition ) {
    bar();
}
Run Code Online (Sandbox Code Playgroud)

此代码的语义将foo()始终运行,然后检查条件.如果为true,则bar()运行,然后返回第一个块(因此foo()再次运行等).感谢reddit用户zxqdms的评论,我了解到Donald E. Knuth在他的论文"使用go to语句进行结构化编程"(参见第279页)中写到了这种结构.

您认为哪些替代控制结构是组织计算的有用方法?

我的目标是为自己和他人提供构建代码的新方法,以改进分块和推理.

注意:我不是在询问如何概括所有可能的控制结构,无论是使用jne,if/ goto,Lisp宏,continuation,monads,组合器,夸克还是其他任何东西.我问的是什么专业在描述代码时很有用.

Jor*_*dão 20

一个相当普遍的是无限循环.我想这样写:

forever {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

  • #define ever(;;)永远{} (17认同)
  • @Jookia:`#define forever for(;;)` (5认同)
  • 最后一个真正的答案! (2认同)

Jor*_*dão 20

有时,我需要一个带索引的foreach循环.它可以写成这样:

foreach (index i) (var item in list) {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

(我不是特别喜欢这种语法,但你明白了)

  • 在python中,这是使用内置的枚举函数来处理的,该函数接受一个列表并返回(索引,项)对的列表."对于i,枚举(列表)中的项目". (10认同)
  • 在Ruby中,我们使用Array#each_with_index (2认同)

Jor*_*dão 18

用else循环:

while (condition) {
  // ...
}
else {
  // the else runs if the loop didn't run
}
Run Code Online (Sandbox Code Playgroud)

  • Python正是这种结构.此外,它允许将'else:'添加到'for:'和'try:'. (6认同)
  • 在Python中,如果循环"正常"终止,则运行else,无论是在没有中断的情况下执行还是从不运行. (3认同)

mun*_*ent 18

大多数语言都有内置函数来覆盖常见的情况,但是"fencepost"循环总是一件苦差事:循环你希望在每次迭代中做某事,并迭代之间做其他事情.例如,使用分隔符连接字符串:

string result = "";
for (int i = 0; i < items.Count; i++) {
    result += items[i];
    if (i < items.Count - 1) result += ", "; // This is gross.
    // What if I can't access items by index?
    // I have off-by-one errors *every* time I do this.
}
Run Code Online (Sandbox Code Playgroud)

我知道折叠可以涵盖这种情况,但有时你想要一些必要的东西.如果你能这样做会很酷:

string result = "";
foreach (var item in items) {
    result += item;
} between {
    result += ", ";
}
Run Code Online (Sandbox Code Playgroud)

  • 在Haskell使用"穿插",这不是一件苦差事,imho. (5认同)

mun*_*ent 14

{
    foo();
} split_while( condition ) {
    bar();
}
Run Code Online (Sandbox Code Playgroud)

您可以使用常规方法轻松完成此操作while:

while (true) {
    foo();
    if (!condition) break;
    bar();
}
Run Code Online (Sandbox Code Playgroud)

我现在经常这样做,因为我克服了我的非理性厌恶break.

  • 这是真的,但我觉得这并没有解决这个问题.我并不特别关心*你如何选择实现这些替代控制结构,无论是`while`和`break`还是(gasp!)甚至是`goto`.我想要*思考*关于代码的方法.我发现split_while让我以一种新的方式思考结构,类似于`while`是对条件跳转的结构改进. (6认同)
  • 这不符合OP问题. (6认同)
  • Ppl没有阅读这个问题.看到这个"答案"最高票被选中是很奇怪的. (4认同)

Has*_*ant 13

如果你看一下Haskell,虽然各种控制结构都有特殊的语法,但控制流通常是按类型捕获的.最常见的这种控件类型是Monads,Arrows和applicative functors.因此,如果你想要一种特殊类型的控制流,它通常是某种高阶函数,你要么自己编写,要么在Haskells包数据库(Hackage)中找到一个非常大的.

这些函数通常位于Control命名空间中,您可以在其中找到用于并行执行错误处理的模块.通常在过程语言中找到的许多控制结构在Control.Monad中都有一个函数副本,其中包括循环和if语句.如果其他是Haskell中keyworded表达,如果没有其他的表达就没有意义了,但非常有意义的单子,所以没有其他的if语句是由功能捕捉whenunless.

另一种常见情况是在更一般的上下文中进行列表操作.功能语言非常喜欢fold,而且专业版本喜欢mapfilter.如果你有一个monad,那么就有了它的自然延伸fold.这就是所谓的foldM,因此也有你可以想到的任何专业版折叠的扩展,比如mapMfilterM.


Man*_*ero 11

这只是一般概念和语法:

if (cond)
   //do something
else (cond)
   //do something
also (cond)
   //do something
else
   //do something
end
Run Code Online (Sandbox Code Playgroud)

始终评估ALSO条件.ELSE像往常一样工作.

它也适用于案例.可能这是消除break语句的好方法:

case (exp)
   also (const)
      //do something
   else (const)
      //do something
   also (const)
      //do something
   else
      //do something
end
Run Code Online (Sandbox Code Playgroud)

可以理解为:

switch (exp)
   case (const)
      //do something
   case (const)
      //do something
      break
   case (const)
      //do something
   default
      //do something
end
Run Code Online (Sandbox Code Playgroud)

我不知道这是有用还是简单,但它是一个例子.


小智 10

使用(lisp风格)宏,尾部调用和延续,这一切都很古怪.

对于宏,如果标准控制流构造对于给定的应用程序来说是不够的,程序员可以编写自己的(以及更多).它只需要一个简单的宏来实现你给出的结构作为例子.

通过尾调用,可以将复杂的控制流模式(例如实现状态机)分解为函数.

Continuations是一个功能强大的控制流原语(try/catch是它们的受限版本).结合尾调用和宏,复杂的控制流模式(回溯,解析等)变得直截了当.此外,它们在Web编程中很有用,因为它们可以反转控制的反转; 你可以有一个功能,要求用户输入一些信息,进行一些处理,要求用户提供更多输入等.

要解释Scheme标准,您应该尝试删除使其他功能显得必要的限制,而不是将更多功能堆积到您的语言上.

  • 这仍然留下了*将要实现的*控制结构的问题.好的,Lisp宏概括了我需要的所有控制结构; 好吧,也许他们不应该是核心语言.这仍然没有回答*我选择哪些*专业.我们历来发现`if`和`while`可能有用 - 还有什么? (6认同)
  • @一个.Rex:实际上,我记不起上次我在某种*非常特殊的*上下文之外使用`while`循环了.我相信最后一次是在一个手写的递归下降解析器中,我将它用作DSL元素而不是实际循环.我通常使用地图,折叠,catamorphisms,过滤器,变压器.我甚至不经常使用普通的迭代器.在现代语言中,使用`while`循环的唯一原因是当你想要一个*无限循环时,例如在操作系统的事件循环中.但是,为此,您可以使用尾递归函数. (5认同)

Jor*_*dão 8

如果不:

unless (condition) {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

而不是:

until (condition) {
  // ...
}
Run Code Online (Sandbox Code Playgroud)


Boo*_*jum 8

标记循环是我发现自己有时从主流语言中丢失的东西.例如,

int i, j;
for outer ( i = 0; i < M; ++i )
    for ( j = 0; j < N; ++j )
        if ( l1[ i ] == l2[ j ] )
           break outer;
Run Code Online (Sandbox Code Playgroud)

是的,我通常可以使用a来模拟这个goto,但是相当于continue需要你在标签之后将增量移动到循环体的末尾,这会损害可读性.您也可以通过在内部循环中设置一个标志并在外部循环的每次迭代中检查它来完成此操作,但它总是看起来很笨拙.

(额外奖励:我有时希望有一个和它redo一起去.它会在没有评估增量的情况下返回到循环的开始.)continuebreak


hel*_*ium 8

我提议"然后"运算符.它在第一次迭代时返回左操作数,在所有其他迭代中返回右操作数:

var result = "";
foreach (var item in items) {
    result += "" then ", ";
    result += item;
}
Run Code Online (Sandbox Code Playgroud)

在第一次迭代中,它将""添加到所有其他添加","的结果中,因此您获得一个字符串,其中包含用逗号分隔的每个项目.

  • 一般的想法很好,但看起来很奇怪. (2认同)
  • 如果有一个新的块允许在for循环内的任何地方...也许有另一个...`first {...} else {result + =","; }` (2认同)

Man*_*ero 8

if (cond)
   //do something
else (cond)
   //do something
else (cond)
   //do something
first
   //do something
then
   //do something
else (cond)
   //do something
else
   //do something
end
Run Code Online (Sandbox Code Playgroud)

如果3个条件中的任何一个被评估为真,则FIRST和THEN块运行.FIRST块在条件块之前运行,THEN在条件块运行之后运行.

FIRST和THEN语句之后的ELSE条件或最终写入独立于这些块.

它可以读作:

if (cond)
   first()
   //do something
   then()
else (cond)
   first()
   //do something
   then()
else (cond)
   first()
   //do something
   then()
else (cond)
   //do something
else
   //do something
end


function first()
   //do something
return
function then()
   //do something
return
Run Code Online (Sandbox Code Playgroud)

这些功能只是一种阅读形式.他们不会创造范围.它更像是来自Basic的gosub/return.

作为讨论事项的实用性和可读性.


Pet*_*son 6

怎么样

alternate {
    statement 1,
    statement 2,
    [statement 3,...]
}
Run Code Online (Sandbox Code Playgroud)

循环通过每个连续通过的可用语句.

编辑:琐碎的例子

table_row_color = alternate(RED, GREEN, BLUE);

player_color = alternate(color_list); // cycles through list items

alternate(
    led_on(),
    led_off()
);
Run Code Online (Sandbox Code Playgroud)

编辑2:在上面的第三个例子中,语法可能有点令人困惑,因为它看起来像一个函数.实际上,每次传递只评估一个语句,而不是两者.更好的语法可能是类似的

alternate {
    led_on();
}
then {
    led_off();
}
Run Code Online (Sandbox Code Playgroud)

或者那种效果.但是我确实喜欢这样的想法,即如果需要可以使用其结果(如颜色示例中所示).


hel*_*ium 5

D的示波器防护装置是一种非常常见的有用控制结构.


Dan*_*bić 5

我想我应该提到CityScript(的脚本语言CityDesk其中有一些非常奇特的循环结构).

从帮助文件:

{$ forEach n var in (condition) sort-order $}
... text which appears for each item ....
{$ between $}
.. text which appears between each two items ....
{$ odd $}
.. text which appears for every other item, including the first ....
{$ even $}
.. text which appears for every other item, starting with the second ....
{$ else $}
.. text which appears if there are no items matching condition ....
{$ before $}
..text which appears before the loop, only if there are items matching condition
{$ after $}
..text which appears after the loop, only of there are items matching condition
{$ next $}
Run Code Online (Sandbox Code Playgroud)