Полезные альтернативные структуры управления? - PullRequest
43 голосов
/ 27 ноября 2010

Иногда, когда я программирую, я обнаруживаю, что какая-то конкретная структура управления была бы очень полезна для меня, но не доступна напрямую в моем языке программирования. Я думаю, что моим самым распространенным желанием является что-то вроде «раздельного времени» (я понятия не имею, как на самом деле это назвать):

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

Семантика этого кода заключается в том, что foo() всегда выполняется, а затем проверяется условие. Если true, то bar() запускается и мы возвращаемся к первому блоку (таким образом, снова запускаем foo() и т. Д.). Благодаря комментарию пользователя reddit zxqdms я узнал, что Дональд Кнут пишет об этой структуре в своей статье «Структурированное программирование с go to операторами» (см. Страницу 279) .

Какие альтернативные управляющие структуры вы считаете полезным для организации вычислений?

Моя цель здесь - дать себе и другим новые взгляды на структурирование кода, чтобы улучшить разбивку на части и рассуждения.

Примечание : я не спрашиваю о том, как обобщить все возможные структуры управления, будь то с помощью jne, if / goto, макросов Lisp, продолжений , монады, комбинаторы, кварки или что-то еще. Я спрашиваю, какие специализации полезны при описании кода.

Ответы [ 28 ]

3 голосов
/ 03 декабря 2010
for int i := 0 [down]to UpperBound() [step 2]

Отсутствует в каждом языке, производном от C.

Пожалуйста, подумайте, прежде чем голосовать или написать комментарий :
Это не избыточно для for (int i = 0; i <= UpperBound(); i++), оно имеет другую семантику:

  1. UpperBound() оценивается только один раз

  2. Случай UpperBound() == MAX_INT не создает бесконечный цикл

3 голосов
/ 28 ноября 2010

Это, вероятно, не считается, но в Python я был расстроен, что не было цикла do.

Для того, чтобы я не получил никаких голосов за этот ответ, меня раздражает любой язык, на котором я работаю, в течение любого периода времени, в котором нет языка.

3 голосов
/ 28 ноября 2010

Это немного шутка, но вы можете получить желаемое поведение, например:

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

ps форматирование было немного сложным, и я определенно не доволен этим;Однако, Emacs делает еще хуже.Кто-нибудь хочет попробовать vim?

2 голосов
/ 12 декабря 2010

Это похоже на ответ @ Пола Кейстера .

(бормотание, бормотание) много лет назад, приложение, над которым я работал, имело множество вариаций так называемого контроля.обработка разрыва - вся эта логика, которая используется для разбиения отсортированных строк данных на группы и подгруппы с верхними и нижними колонтитулами.Поскольку приложение было написано на LISP, мы собрали общие идиомы в макросе WITH-CONTROL-BREAKS.Если бы я перенес этот синтаксис в популярную волнистую форму, он мог бы выглядеть примерно так:

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

В эту современную эпоху, с широко распространенными SQL, XQuery, LINQ и т. Д., Эта потребностькажется, не возникает так много, как раньше.Но время от времени мне бы хотелось, чтобы под рукой была эта структура управления.

2 голосов
/ 28 ноября 2010
foo();

while(condition)
{
   bar();
   foo();
}
1 голос
/ 15 ноября 2011

Одной из структур управления, которая недоступна во многих языках, является структура типа case-in. Подобно структуре типа переключателя, она позволяет вам иметь аккуратно отформатированный список возможных опций, но соответствует первой верной (а не первой, соответствующей входным данным). LISP такого (который есть):

(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

Или для тех, кто предпочитает более C-подобный формат

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

Это, в сущности, более точное представление конструкции if/elseif/elseif/else, чем у переключателя, и он может быть чрезвычайно полезен для выражения этой логики чистым, читабельным способом.

1 голос
/ 02 декабря 2010

Как насчет PL / I-стиля "для" циклов? Эквивалент VB будет:

' Counts 1, 2, ... 49, 50, 23, 999, 998, ..., 991, 990
  For I = 1 to 50, 23, 999 to 990 Step -1

Самое распространенное использование, которое я вижу, это запустить цикл для списка индексов, а затем добавить еще один. Кстати, использование For-Each также может быть удобно:

' Bar1, Bar2, Bar3 are an IEnum(Wazoo); Boz is a Wazoo
  For Each Foo as Wazoo in Bar1, Bar2, Enumerable.One(Boz), Bar3

Это запустит цикл для всех предметов в Bar1, всех предметов в Bar2, Boz и Bar3. Linq, вероятно, разрешил бы это без особых проблем, но встроенная поддержка языка могла бы быть немного более эффективной.

0 голосов
/ 06 июня 2012

Как насчет перебора с движущимся окном (из n элементов вместо 1) через список? Я думаю, что это связано с тангенциальным ответом @ munificent .

Что-то вроде

#python
#sum of adjacent elements
for x,y in pairs(list):
    print x + y

def pairs(l):              
    i=0                    
    while i < len(l)-1:    
        yield (l[i],l[i+1])
        i+=1               

Это полезно для определенных типов вещей. Не поймите меня неправильно, это легко реализовать как функцию, но я думаю, что многие люди пытаются создать циклы for и while, когда есть более конкретные / описательные инструменты для работы.

...