web-dev-qa-db-ja.com

知っている便利な代替制御構造はどれですか。

同様の質問 はSOでクローズされました。

プログラミングをしているときに、特定の制御構造が非常に役立つ場合がありますが、プログラミング言語では直接利用できません。

計算を整理するための有用な方法であると思う代替制御構造は何ですか?

ここでの目標は、チャンクと推論を改善するために、コードの構造化について新しい考え方を身につけることです。

現在利用できない希望的な構文/セマンティクスを作成するか、既存のプログラミング言語であまり知られていない制御構造を引用できます。

回答は、新しいプログラミング言語または実際の言語を拡張するためのアイデアを提供する必要があります。

これはブレーンストーミングと考えてください。クレイジーなアイデアだと思うものを投稿してください。

それは命令型プログラミングについてです。

12
Maniero

OK、これは面白い質問です。

firstテストで条件がtrueでない場合の一般的なelse for whileループとforループも必要です。

while (condition) {
    // process
}
else {
    // condition was never true
}

これにより、条件の厄介な再計算や変数への格納が回避されます。

14
Macneil

いくつかの答えを1つにまとめてみませんか?

while (expr) {

    // Executed every iteration, unless first{} is present.
    // May be explicitly called rest{} if you like first{} to come first.

    // Blocks may return results, and consequently be used in expressions.
    return expr;

} first {

    // Executed only on the first iteration.

} pre {

    // Executed before every iteration.

} post {

    // Executed after every iteration.

} catch (oops) {

    // All blocks are implicitly try{}ed if followed by a catch{}.

} finally {

    // Executes after the block completes, regardless of exceptions.

} else {

    // Executed if the loop body or rest{} never executes.

} never {

    // Executes only when a client is present.

} drop (bad, worse), // Explicitly ignore certain exceptions.
  until (expr);      // Here, have a post-body condition, too.

命令型言語で拡張可能な一般化されたフロー制御構文は、かなり便利で面白いでしょう。それが表示されるまでは、LISPか何かを使用すると思います。

10
Jon Purdy

関数として構造を制御します。

forifelsewhileなどを特別な構造ではなく関数にしたい。

returntry/exceptおよびgotoを継続の導関数にしたい。

もちろん、これは特定の制御構造ではなく、制御構造のメタである制御構造の一般的な見方に関係しています。

7
dietbuddha

リンクされた記事は、ドナルドクヌースのN + 1/2ループについて正しく理解しています。 C/C++/Javaで表現:

_for (;;) {
  get next element;
  if (at the end) break;
  process the element;
}
_

これは、ファイルから行または文字を読み取り、EOFに達したかどうかをテストしてから処理するのに役立ちます。 for(;;)..if(..)break;というパターンが慣用的であるように見えるのに慣れています。 (Knuthの記事を読む前は、本Literate Programmingに転載されていましたが、これは「wtf?」でした。)

Knuthはキーワード_loop/while/repeat_を提案しました:

_loop:
  S;
while C:
  T;
repeat
_

ここで、SおよびTは、一連の0個以上のステートメントのプレースホルダーであり、Cはブール条件です。 Sステートメントがない場合は、whileループであり、Tステートメントがない場合は、doループです。

この構造自体は、0個以上の_while C_句を許可することで一般化でき、無限ループを表現し、2つのチェックが必要になるいくつかのまれな条件を表現するのに最適です。

同じ記事で、Knuthは、(gotoを使用する代わりに)スロー/キャッチ例外のローカルバージョンとなるシグナリングメカニズムを提案しました。

私のために? Java末尾呼び出しの最適化をサポートし、必要に応じてany一般的な制御構造を表現できるように)。


pdate:多くのC/C++/Javaプログラマがwhileの条件に埋め込まれた割り当てを使用してこれを回避することを忘れていました:

_while ((c = getc(f)) != -1) {
   T;
}
_

Knuthの構成からの用語を使用すると、SCを単一の式に組み合わせることができる場合、これは許容されます。上記の埋め込み割り当てを見るのを嫌う人もいれば、上記のfor (;;)breakを見るのを嫌う人もいます。ただし、SCを組み合わせることができない場合(Sに複数のステートメントがある場合など)は、for (;;)が、コードを繰り返さない唯一の選択肢です。もう1つの方法は、Sコードを単純に複製することです。

_S;
while (C) {
  T;
  S;
}
_

Knuthの_loop/while/repeat_の方がはるかに優れているようです。

6
Macneil
unless(condition) {
  // ...
}

同じことをします:

if(!condition) {
  // ...
}

repeat {
  // ...
} until(condition)

同じことをします:

do {
  // ...
} while(!condition)
6
missingfaktor

BCPL言語には valueof expression があり、一連のステートメントを単一の式に変換するために使用できます。

_foo(a, b, valueof {some series of statements; resultis v});
_

ここで、_some series of statements_は何でもかまいません。valueof全体はvと評価されます。

これは、Javaで、this()またはsuper()を呼び出すための引数を計算する必要がある場合に便利です(その前に何も起こらないことが必要です)。もちろん、別のメソッドを作成することもできますが、コンテキストに多くのローカル値を渡す必要がある場合は、面倒な場合があります。

必要な変数にfinalを使用できる場合は、すでに匿名インナークラスを使用してvalueof in Javaを実行できます。

_foo(a, b, new Object(){String valueof(){
    String v ...; some series of statements; return v;}}.valueof());
_
6
Macneil

いわゆる「ダイクストラのループ」(「ダイクストラの保護ループ」とも呼ばれます)があります。 The Guarded Command Language(GCL) で定義されています。上記のWikipediaの記事 6 Repetition:do の構文とセマンティックに関するいくつかの情報を見つけることができます。

今日、私は実際にこの制御構造を直接サポートする1​​つのプログラミング言語を知っています。 Oberon-07 (PDF、70 KB)です。また、whileステートメントの形式で「ダイクストラのループ」をサポートします。セクション9.6をご覧ください。上記PDFのWhileステートメント。

WHILE m > n DO m := m – n 
ELSIF n > m DO n := n – m 
END

追伸これは my SO answer のコピーです。

5
Wildcat

別の見方をすれば、プログラミング言語でのイテレーターのより良いサポートを期待しています。特に、2つのコレクションをペアで表示したい場合

for (String s, Integer i : stringsSet, integersSet) {
    // use the pair (s, i)
}

いくつかの動的言語はすでにこれを持っているか、ライブラリやマクロを介して簡単にサポートしているかもしれませんが、これはあなたの質問の精神にあると思います。

2つのセットのサイズが同じでない場合、例外がスローされるか、ループの後にelseを指定して、サイズに違いがあることを通知できます。

当然、3つ以上のリストを下に移動するためにこれを一般化できます。


pdate:反復可能オブジェクト間でデカルト積を実行することも役立ちます。

for (String s, Integer i : stringsSet * integersSet) {
    // use the pair (s, i), each s with each i
}

ネストされたループにすぎません:

for (String s : stringsSet) {
    for (Integer i : integersSet) {
        // use the pair (s, i), each s with each i
    }
}

ここで提供した2つの表記法の間で、ペアの数にO(n)とO(n ^ 2)の違いがあること、単一の文字の変更。

5
Macneil

これは単なる一般的な考え方と構文です。

if (cond)
   //do something
else (cond)
   //do something
also (cond)
   //do something
else
   //do something
end

ALSO条件は常に評価されます。 ELSEは通常どおり機能します。

ケースにも使えます。おそらくそれはbreakステートメントを削除する良い方法です:

case (exp)
   also (const)
      //do something
   else (const)
      //do something
   also (const)
      //do something
   else
      //do something
end

次のように読むことができます:

switch (exp)
   case (const)
      //do something
   case (const)
      //do something
      break
   case (const)
      //do something
   default
      //do something
end

これが読みやすいかどうかはわかりませんが、例です。

4
Maniero

バックトラッキングが組み込まれたアイコンスタイルの式。

Pythonには、アイコンジェネレーターの多くの利点があり、一般的にはIMOの方が優れています。そして原則として、バックトラッキングは一種の例外スローでしたが、それは表現の単純さであり、それに相当するものは...

_x = (a / b) else c;
_

ゼロによる除算のようなフェイルケースを処理するため。

アイコンが不自然になった場所-ブール値を返す比較演算子はありません。比較は常に成功するか、バックトラックをトリガーしました。また、他のセマンティックな問題があり、私は必死にそれを覚えようとしています...まあ、それはおそらく忘れられているより抑圧されているとしましょう。

他の部分がないif式が必要だといつも思っていました-if (condition, success-value)のようなもので、条件がfalseを返した場合はバックトラックし、奇妙な比較を削除します。

[〜#〜] edit [〜#〜]覚えています。 2つの引数との比較は成功または失敗します-返す新しい値を計算しません。それで成功すると、何が返されますか?答え-議論の一つ。しかし、あなたが_a > b_を書くなら、それは-aまたはb?を返すための論理的な引数です。そして、代わりに_b < a_と書くとどうなるでしょうか?私think常に正しい引数を返しましたが、これは何とでも同じように理にかなっていますが、それでも通常は間違った引数のように見えました。

4
Steve314
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

3つの条件のいずれかがtrueと評価された場合、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

これらの関数は、読み取るフォームにすぎません。それらはスコープを作成しません。 Basicからのgosub/returnに似ています。

議論の問題としての有用性と読みやすさ。

3
Maniero

継続渡しスタイル が思い浮かびます。次に、もちろん Tail Call Optimization も必要です。

3
pillmuncher

シームレスなスレッド分岐、関数のような構文を持っていますが、別のスレッドで実行され、最初に渡されていないデータにアクセスできません。

branch foo(data, to, be, processed){
    //code
    return [resulting, data]
}

ブランチが呼び出されると、すぐにハンドルが返されます。

handle=foo(here, is, some, data)

ハンドルを使用して、タスクが完了したかどうかを確認できます。

handle.finished() //True if the execution is complete

実行が完了する前に結果が要求された場合、メインスレッドは単に待機します。

[result, storage]=handle.result()

これは、より高度なマルチスレッドシナリオをカバーするのではなく、複数のコアの利用を開始する簡単にアクセスできる方法を提供します。

3
aaaaaaaaaaaa

最初のイテレーションで何か違うことをする必要のあるループを書いていることがあります。たとえば、<td>タグの代わりに<th>タグを表示します。

この状況はブールフラグで処理します。このようなもの:

first = true

while (some_condition)
    if (first)
        do_something
        first = false
    else
        do_something_else

firstの値をほとんどの場合にfalseになる可能性があるすべての反復でチェックするのはばかげているようです。

最初の反復で別のループ本体を指定するためのループオプションが欲しいのですが。別の変数は必要ありません。生成されたコードには最初の反復用と残りの反復用の2つの本体があるため、コンパイルされたコードも1つは必要ありません。

2
Barry Brown

私には2つのアイデアがあります。

多くの場合、catchブロックで 自分自身を繰り返す であることがわかります。これはメソッドを抽出することでいくらか助けることができますが、メソッドが非常に短いか、またはメソッドに値しない場合、不要な混乱を引き起こす可能性があります。したがって、catchブロックをネストするのは良いことです。

try {
    // Save something
} catch (Exception e) {
    // Something we do for all Exceptions
    catch (ProcessingException e) {
        // Something we do for all Processing exceptions
        catch (DBExcpetion e) {
            // DBExceptions are a subclass of ProcessingException
        }
        catch (BusinessRuleException e) {
            // BusinessRuleExceptions are also a subclass of ProcessingException
        }
    }
    // Something we do after specific sub class Exceptions
 }

Webプログラミングでは、次のようなことをすることがよくあります(これは実際の例ではないため、架空のケースを分析しないでください)。

Account a = getSavedAccount();
if (a == null) {
    a = getAccountFromSessionId();
}
if (a == null) {
    a = getAccountFromCookieId();
}
if (a == null) {
    a = createNewAccount();
}

Javascript(まあ、ECMAScript、そしておそらく私が慣れていない他のもの)では、どんな値でも条件として評価できるので、|| 助けられる。

var a = getAFromLocation1() || getAFromLocation2() || default;

私はそれがどのように見えるかが本当に好きで、もっと多くの言語、特にサーバー側のいくつかがそれをサポートしてくれることを望みます。 (PHPはあらゆるものを条件として評価できますが、値を保持する代わりに、条件式全体をブール値に変換します。PythonまたはRubyについては知りません。)3つの後で扱いにくくなる可能性があります。ケースなどはありますが、3つを超えるケースがある場合は、ソフトウェアの設計も悪い可能性があります。

1
Nicole

[stackoverflowの自分の回答からコピー]


ignoring-特定のコードブロックで発生する例外を無視します。

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

無視する制御構造を使用すると、次のように簡潔かつ読みやすく記述できます。

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

[Scalaは、util.controlパッケージの標準ライブラリでこれ(および他の多くの例外処理制御構造)を提供します。]

1
missingfaktor

一般化されたスイッチは上記で述べています:

 switch(x){
  predicate1:
     dosomething();
  predicate2:
     dosomethingelse();
 }

ハスケルで:

  switch' :: a -> [(a -> Bool, b)] -> b
  switch' a [] = undefined
  switch' a (f,b):xs = if f a
                     then b
                      else switch' a xs
1
John John

の代わりに:

switch(myEnum) {
  case MyEnum.Val1: do1(); ...
  case MyEnum.Val2: do2(); ...
....

Pythonを実行するか、C#の方法で実行します。

action = val2func[myEnum]
action()

Scalaには多くの新機能があります。

最後に、Clojureなどの言語を拡張して、追加の機能を提供できます。

1
Job

C#では、単純なswitch () { ... }を使用したいと思いますが、次のような式で拡張できます。

switch (value)
{
  // string-based operators:
  case begins "Maria": // to catch Maria Carey
    break;
  case ends "Washington": // to catch George Washington
    break;
  case like "ph": // to catch Phil, Phillip, Sophie
    break;
  case between "Aaron" and "April": // to catch all names between
    break;

  // use non-static variables in case expression:
  case Dao.GetDefaultBabyName():
    break;

  // continuable cases without breaking
  case "John":
    bonus = 25;
  case "Peter":
    salary = 500;
    break;

  // jumps between cases
  case "Aleron":
    // do something
    break;
  case "Bella":
    // do something
    jump "Aleron";
    break;

}

等々。数値または他の型と同じ(IComparableIConvertible、...をサポート)

これは私のコードをより簡潔で読みやすくするかもしれません。

0
Genius

@Macneilが言ったように、それは楽しい質問です。

私の(謙虚な咳)が発見した私のお気に入りの異常な制御構造は、 差分実行 です。

特定の用途があります。私にとって、圧倒的な使用法はユーザーインターフェイスのプログラミングです。これは、冗長データを対応して維持するという、より一般的な問題の一例です。一方で、アプリケーションデータがあり、もう一方には、同意する必要があるUIコントロールがあります。これは「拘束力」のように聞こえますが、実際にはもっと多くのことがあります。

通常、CまたはC++のマクロで実装します。 C#では、ステートメントを手動で展開する必要があります。それは苦痛ですが、うまくいきます。

LISPマクロの観点から実装した後は、非常にクリーンでした。プログラマ側の注意は必要ありませんでした。完全なパーサーを作成して適切なものをすべて生成するのに苦労した場合、他の構造化言語でも同じことができたでしょう。それは大きなプロジェクトであり、私はそれをしていません。

0
Mike Dunlavey

最も単純なforループ-

for(100)
{
    //Will run for 100 times
}


for(i)
{
    //Will run for i times while i must be a positive integer
}


for(i as a)
{
    //Will run for i times while i must be a positive integer
    //and a is the incremental loop variable starting from 0 and 
    //scoped within the loop
}


for(i as a=2)
{
    //Will run for i times while i must be a positive integer
    //and a is the incremental loop variable starting from 2 and 
    //scoped within the loop
}
0
Gulshan

forのような「従来の」制御構造とは、働く男性を支配し、支配する資本家エリートの腐敗したイデオロギーに服従することです。そのため、代わりにph0rなどの代替制御構造を使用します。 forに似ていますが、より過激です。スーツとネクタイを着てph0rを捕まえて、企業のBSを噴き出すことはありません。 ph0rはそれを現実のものにします。

力と戦え!

0
j_random_hacker