Loops 有用的替代控制结构?
有时在编程时,我发现某些特定的控制结构对我非常有用,但在我的编程语言中并不直接可用。我认为我最常见的愿望是“分手”(我不知道该怎么称呼这个): 此代码的语义是始终运行Loops 有用的替代控制结构?,loops,programming-languages,control-structure,Loops,Programming Languages,Control Structure,有时在编程时,我发现某些特定的控制结构对我非常有用,但在我的编程语言中并不直接可用。我认为我最常见的愿望是“分手”(我不知道该怎么称呼这个): 此代码的语义是始终运行foo(),然后检查条件。如果为true,则运行bar(),然后返回第一个块(因此再次运行foo(),以此类推)。多亏了,我知道Donald E.Knuth在他的论文中写到了这种结构(见第279页) 您认为哪些替代控制结构是组织计算的有效方法? 我在这里的目标是给我自己和其他人新的思考代码结构的方法,以改进分块和推理 注意:我不是问
foo()
,然后检查条件。如果为true,则运行bar()
,然后返回第一个块(因此再次运行foo()
,以此类推)。多亏了,我知道Donald E.Knuth在他的论文中写到了这种结构(见第279页)
您认为哪些替代控制结构是组织计算的有效方法?
我在这里的目标是给我自己和其他人新的思考代码结构的方法,以改进分块和推理
注意:我不是问如何概括所有可能的控制结构,无论是使用jne
,if
/goto
,Lisp宏,continuations,monad,combinator,quark还是其他什么。我想问的是,在描述代码时,哪些专门化是有用的
{
foo();
} split_while( condition ) {
bar();
}
使用常规的,您可以非常轻松地完成此任务,而:
while (true) {
foo();
if (!condition) break;
bar();
}
我现在经常这样做,因为我已经克服了我对使用(lisp风格)宏、尾部调用和延续的break
的非理性厌恶。所有这些都很奇怪
对于宏,如果标准的控制流构造对于给定的应用程序来说是不够的,程序员可以编写自己的(等等)。它只需要一个简单的宏来实现您作为示例给出的构造
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
通过尾部调用,可以将复杂的控制流模式(如实现状态机)分解为函数
Continuations是一个强大的控制流原语(try/catch是它们的受限版本)。结合尾部调用和宏,复杂的控制流模式(回溯、解析等)变得直截了当。此外,它们在web编程中很有用,因为使用它们可以反转控制反转;您可以使用一个函数,要求用户进行一些输入、进行一些处理、要求用户进行更多输入等
为了解释Scheme标准,您不应该在您的语言中添加更多的功能,而应该设法消除使其他功能显得必要的限制。还要注意,许多控件结构在一元上下文中获得了新的含义,这取决于特定的一元-查看mapM、filterM、whileM、,Haskell中的sequence等。如果您查看Haskell,尽管各种控制结构都有特殊的语法,但控制流通常由类型捕获。最常见的此类控件类型是单子、箭头和应用程序函子。因此,如果您想要一种特殊类型的控制流,它通常是某种高阶函数,您可以自己编写,也可以在Haskells package database(Hackage)中找到一个,它相当大
这类函数通常位于控制命名空间中,您可以在其中找到用于并行执行以进行错误处理的模块。过程语言中的许多控制结构通常都有一个对应于control.Monad的函数,其中包括循环和if语句。If-else在haskell中是一个关键字表达式,If-without-else在表达式中没有意义,但在monad中完全有意义,因此函数when
和会捕获If-without-else语句,除非
另一种常见情况是在更一般的上下文中执行列表操作。函数式语言非常喜欢折叠
,专门的版本有map
和filter
。如果你有一个单子,那么它有一个自然的扩展fold
。这被称为foldM
,因此也有你能想到的任何专门版本的fold的扩展,比如mapM
和filterM
这有点开玩笑,但是你可以得到你想要的行为,就像这样:
#include <iostream>
#include <cstdlib>
int main (int argc, char *argv[])
{
int N = std::strtol(argv[1], 0, 10); // Danger!
int state = 0;
switch (state%2) // Similar to Duff's device.
{
do {
case 1: std::cout << (2*state) << " B" << std::endl;
case 0: std::cout << (2*state+1) << " A" << std::endl; ++state;
} while (state <= N);
default: break;
}
return 0;
}
forever {
// ...
}
foreach (index i) (var item in list) {
// ...
}
foreach(var val in dataSource)
groupon(val.CustomerID)
{
startgroup
{
WriteHeader(val);
}
endgroup
{
WriteFooter(val)
}
}
each
{
WriteRow(val);
}
withControlBreaks (x, y, z : readSortedRecords()) {
first (x) : { emitHeader(x); subcount = 0; }
first (x, y) : { emitSubheader(x, y); zTotal = 0; }
all (x, y, z) : { emitDetail(x, y, z); ztotal += z; }
last (x, y) : { emitSubfooter(x, y, zTotal); ++subCount; }
last (x) : { emitFooter(x, subcount); }
}
#包括
#包括
int main(int argc,char*argv[])
{
int N=std::strtol(argv[1],0,10);//危险!
int state=0;
开关(状态%2)//类似于达夫的设备。
{
做{
案例1:std::cout一个非常常见的是无限循环。我想这样写:
#include <iostream>
#include <cstdlib>
int main (int argc, char *argv[])
{
int N = std::strtol(argv[1], 0, 10); // Danger!
int state = 0;
switch (state%2) // Similar to Duff's device.
{
do {
case 1: std::cout << (2*state) << " B" << std::endl;
case 0: std::cout << (2*state+1) << " A" << std::endl; ++state;
} while (state <= N);
default: break;
}
return 0;
}
forever {
// ...
}
foreach (index i) (var item in list) {
// ...
}
foreach(var val in dataSource)
groupon(val.CustomerID)
{
startgroup
{
WriteHeader(val);
}
endgroup
{
WriteFooter(val)
}
}
each
{
WriteRow(val);
}
withControlBreaks (x, y, z : readSortedRecords()) {
first (x) : { emitHeader(x); subcount = 0; }
first (x, y) : { emitSubheader(x, y); zTotal = 0; }
all (x, y, z) : { emitDetail(x, y, z); ztotal += z; }
last (x, y) : { emitSubfooter(x, y, zTotal); ++subCount; }
last (x) : { emitFooter(x, subcount); }
}
有时,我需要一个带有索引的foreach循环。它可以这样写:
#include <iostream>
#include <cstdlib>
int main (int argc, char *argv[])
{
int N = std::strtol(argv[1], 0, 10); // Danger!
int state = 0;
switch (state%2) // Similar to Duff's device.
{
do {
case 1: std::cout << (2*state) << " B" << std::endl;
case 0: std::cout << (2*state+1) << " A" << std::endl; ++state;
} while (state <= N);
default: break;
}
return 0;
}
forever {
// ...
}
foreach (index i) (var item in list) {
// ...
}
foreach(var val in dataSource)
groupon(val.CustomerID)
{
startgroup
{
WriteHeader(val);
}
endgroup
{
WriteFooter(val)
}
}
each
{
WriteRow(val);
}
withControlBreaks (x, y, z : readSortedRecords()) {
first (x) : { emitHeader(x); subcount = 0; }
first (x, y) : { emitSubheader(x, y); zTotal = 0; }
all (x, y, z) : { emitDetail(x, y, z); ztotal += z; }
last (x, y) : { emitSubfooter(x, y, zTotal); ++subCount; }
last (x) : { emitFooter(x, subcount); }
}
(我不是特别喜欢这种语法,但你知道了)怎么样
alternate {
statement 1,
statement 2,
[statement 3,...]
}
用于循环浏览每个连续过程中的可用语句
编辑:琐碎的例子
table_row_color = alternate(RED, GREEN, BLUE);
player_color = alternate(color_list); // cycles through list items
alternate(
led_on(),
led_off()
);
编辑2:在上面的第三个示例中,语法可能有点混乱,因为它看起来像一个函数。事实上,每次传递只计算一条语句,而不是两条语句。更好的语法可能是
alternate {
led_on();
}
then {
led_off();
}
不过,我很喜欢这样的想法,即如果需要,可以使用which ever调用的结果(如颜色示例中所示)。如果没有:
unless (condition) {
// ...
}
虽然不是:
until (condition) {
// ...
}
忽略
-忽略特定代码块中发生的异常
try {
foo()
} catch {
case ex: SomeException => /* ignore */
case ex: SomeOtherException => /* ignore */
}
使用忽略
控件构造,您可以更简洁易懂地编写它,如下所示:
ignoring(classOf[SomeException], classOf[SomeOtherException]) {
foo()
}
[Scala在其标准库中,在util.control
package中提供了这个(以及许多其他异常处理控件构造)。]与else循环:
while (condition) {
// ...
}
else {
// the else runs if the loop didn't run
}
如果您主要使用非函数式语言,那么Python中的生成器真的很新颖。更一般的情况是:延续、协同例程、惰性列表。这可能不算,但在Python中,我对没有do循环感到不安
为了确保我的答案不会被否决,我在任何一段时间内都会对我所使用的任何一种语言感到恼火,因为这些语言都缺少goto's。标记的循环是我发现自己缺少的一些东西
for int i := 0 [down]to UpperBound() [step 2]
bool found = false;
for (int i = 0; i < N; i++) {
if (hasProperty(A[i])) {
found = true;
DoSomething(A[i]);
break;
}
}
if (!found) {
...
}
for (int i = 0; i < N; i++) {
if (hasProperty(A[i])) {
DoSomething(A[i]);
break;
}
} ifnotinterrupted {
...
}
int lastValue = 0;
foreach (var val in dataSource)
{
if (lastValue != val.CustomerID)
{
WriteFooter(lastValue);
WriteHeader(val);
lastValue = val.CustomerID;
}
WriteRow(val);
}
if (lastValue != 0)
{
WriteFooter(lastValue);
}
foreach(var val in dataSource)
groupon(val.CustomerID)
{
startgroup
{
WriteHeader(val);
}
endgroup
{
WriteFooter(val)
}
}
each
{
WriteRow(val);
}
{$ 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 $}
withControlBreaks (x, y, z : readSortedRecords()) {
first (x) : { emitHeader(x); subcount = 0; }
first (x, y) : { emitSubheader(x, y); zTotal = 0; }
all (x, y, z) : { emitDetail(x, y, z); ztotal += z; }
last (x, y) : { emitSubfooter(x, y, zTotal); ++subCount; }
last (x) : { emitFooter(x, subcount); }
}
(cond
((evenp a) a) ;if a is even return a
((> a 7) (/ a 2)) ;else if a is bigger than 7 return a/2
((< a 5) (- a 1)) ;else if a is smaller than 5 return a-1
(t 17)) ;else return 17
cond
(a % 2 == 0):
a; break;
(a > 7):
a / 2; break;
(a < 5):
a - 1; break;
default:
17; break;