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

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

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

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

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

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

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

Ответы [ 28 ]

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

Я предлагаю оператор «тогда». Он возвращает левый операнд на первой итерации и правый операнд на всех других итерациях:

var result = "";
foreach (var item in items) {
    result += "" then ", ";
    result += item;
}

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

8 голосов
/ 28 ноября 2010
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 и THEN запускаются, если любое из 3 условий оценивается как true. Первый блок выполняется до условного блока, а затем - после выполнения условного блока.

Условная или окончательная запись ELSE после операторов FIRST и THEN не зависит от этих блоков.

Может читаться как:

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

Эти функции - просто форма для чтения. Они не будут создавать возможности. Это больше похоже на госуб / возврат из Basic.

Полезность и читаемость как предмет обсуждения.

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

Как насчет

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

Edit 2 : в третьем примере выше синтаксис может быть немного запутанным, так как выглядит как функция.Фактически, только один оператор оценивается на каждом проходе, а не оба.Лучшим синтаксисом может быть что-то вроде

alternate {
    led_on();
}
then {
    led_off();
}

или что-то в этом роде.Однако мне нравится идея, что результат, который когда-либо вызывался, может быть использован при желании (как в примерах цвета).

5 голосов
/ 03 декабря 2010

Думаю, мне следует упомянуть 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 $}
5 голосов
/ 28 ноября 2010

D ограничители области видимости - это полезная структура управления, которая встречается не очень часто.

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

ignoring - игнорировать исключения, возникающие в определенном блоке кода.

try {
  foo()
} catch {
  case ex: SomeException => /* ignore */
  case ex: SomeOtherException => /* ignore */
}

С помощью управляющей конструкции ignoring вы можете написать ее более кратко и более наглядно, как:

ignoring(classOf[SomeException], classOf[SomeOtherException]) {
  foo()
}

[Scala предоставляет это (и многие другие конструкции управления обработкой исключений) в своей стандартной библиотеке в пакете util.control. ]

4 голосов
/ 03 декабря 2010

Я хотел бы видеть ключевое слово для группировки выходных данных. Вместо этого:

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

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

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

Также обратите внимание, что многие управляющие структуры получают новое значение в монадическом контексте, в зависимости от конкретной монады - посмотрите на mapM, filterM, whileM, sequence и т. Д. В Haskell.

4 голосов
/ 03 декабря 2010

То, что заменяет

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 {
  ...
}

Я всегда чувствую, что должен быть лучший способ, чем ввод флага, просто выполнить что-то после последнего (регулярного) выполнения тела цикла. Можно проверить !(i < N), но i выходит за рамки после цикла.

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

Генераторы в Python являются действительно новыми, если вы в основном работали с нефункциональными языками. В более общем плане: продолжения, сопрограммы, ленивые списки.

...