Useful alternative control structures?

2019-03-08 02:01发布

Sometimes when I am programming, I find that some particular control structure would be very useful to me, but is not directly available in my programming language. I think my most common desire is something like a "split while" (I have no idea what to actually call this):

{
    foo();
} split_while( condition ) {
    bar();
}

The semantics of this code would be that foo() is always run, and then the condition is checked. If true, then bar() is run and we go back to the first block (thus running foo() again, etc). Thanks to a comment by reddit user zxqdms, I have learned that Donald E. Knuth writes about this structure in his paper "Structured programming with go to statements" (see page 279).

What alternative control structures do you think are a useful way of organizing computation?

My goal here is to give myself and others new ways of thinking about structuring code, in order to improve chunking and reasoning.

Note: I'm not asking about how to generalize all possible control structures, whether by using jne, if/goto, Lisp macros, continuations, monads, combinators, quarks, or whatever else. I'm asking what specializations are useful in describing code.

28条回答
Explosion°爆炸
2楼-- · 2019-03-08 02:19

One of the control structures that isn't available in many languages is the case-in type structure. Similar to a switch type structure, it allows you to have a neatly formatted list of possible options, but matches the first one that's true (rather then the first one that matches the input). A LISP of such such (which does have it):

(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

Or, for those that would prefer a more C-like format

cond 
    (a % 2 == 0): 
        a;     break;
    (a > 7):
        a / 2; break;
    (a < 5):
        a - 1; break;
    default:
        17;    break;

It's basically a more accurate representation of the if/elseif/elseif/else construct than a switch is, and it can come in extremely handing in expressing that logic in a clean, readable way.

查看更多
爷的心禁止访问
3楼-- · 2019-03-08 02:19

One that's fairly common is the infinite loop. I'd like to write it like this:

forever {
  // ...
}
查看更多
虎瘦雄心在
4楼-- · 2019-03-08 02:21
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

FIRST and THEN blocks runs if any of 3 conditionals are evaluated to true. FIRST block runs before the conditional block and THEN runs after the conditional block has ran.

ELSE conditional or final write following FIRST and THEN statement are independent from these blocks.

It can read as :

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

These functions are just a form to read. They wouldn't create scope. It's more like a gosub/return from Basic.

Usefulness and readability as matter of discussion.

查看更多
SAY GOODBYE
5楼-- · 2019-03-08 02:22

This is similar to the response by @Paul Keister.

(mumble, mumble) years ago, the application I was working on had lots of variations of so-called control-break processing -- all that logic that goes into breaking sorted rows of data into groups and subgroups with headers and footers. As the application was written in LISP, we had captured the common idioms in a macro called WITH-CONTROL-BREAKS. If I were to transpose that syntax into the ever-popular squiggly form, it might look something like this:

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); }
}

In this modern era, with widespread SQL, XQuery, LINQ and so on, this need does not seem to arise as much as it used to. But from time to time, I wish that I had that control structure at hand.

查看更多
小情绪 Triste *
6楼-- · 2019-03-08 02:24

I'd like to see a keyword for grouping output. Instead of this:

        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);
        }

how about something like this:

        foreach(var val in dataSource)
        groupon(val.CustomerID)
        {            
            startgroup
            {
                WriteHeader(val);
            }
            endgroup
            {
                WriteFooter(val)
            }
        }
        each
        {
            WriteRow(val);
        }

If you have a decent platform, controls, and/or reporting formatting you won't need to write this code. But it's amazing how often I find myself doing this. The most annoying part is the footer after the last iteration - it's hard to do this in a real life example without duplicating code.

查看更多
再贱就再见
7楼-- · 2019-03-08 02:24

Something that replaces

bool found = false;
for (int i = 0; i < N; i++) {
  if (hasProperty(A[i])) {
    found = true;
    DoSomething(A[i]);
    break;
  }
}
if (!found) {
  ...
}

like

for (int i = 0; i < N; i++) {
  if (hasProperty(A[i])) {
    DoSomething(A[i]);
    break;
  }
} ifnotinterrupted {
  ...
}

I always feel that there must be a better way than introducing a flag just to execute something after the last (regular) execution of the loop body. One could check !(i < N), but i is out of scope after the loop.

查看更多
登录 后发表回答