アルゴール60
ここにboolean procedure
質問が求めることを行うa があります(注:Algol 60はトークンのリストに関して定義されており、構文は修正されていません。以下では、プログラムを構成する個々のトークンを表すためにMarst構文を使用しています):
boolean procedure recursion detector(n);
boolean n;
begin
own boolean nested, seen nested;
boolean was nested, retval;
was nested := nested;
begin if nested then seen nested := true end;
nested := true;
retval := n; comment "for the side effects, we ignore the result";
nested := was nested;
retval := seen nested;
begin if ! nested then seen nested := false end;
recursion detector := retval
end;
検証
これが私が使ったテストコードです:
procedure outboolean(c, b);
integer c;
boolean b;
begin
if b then outstring(c, "true\n") else outstring(c, "false\n")
end;
begin
outboolean(1, recursion detector(false));
outboolean(1, recursion detector(true));
outboolean(1, recursion detector(recursion detector(false)));
outboolean(1, recursion detector(false | recursion detector(true)));
outboolean(1, recursion detector(false & recursion detector(true)));
outboolean(1, recursion detector(recursion detector(recursion detector(false))))
end
予想通り、出力は次のとおりです。
false
false
true
true
true comment "because & does not short-circuit in Algol 60";
true
説明
Algol 60は、ほとんどの言語とは異なる評価順序を持っています。これは独自のロジックを備えており、実際には一般的な評価順序よりもはるかに強力で一般的ですが、人間が頭を回すのはかなり困難です(また、コンピューターを効率的に実装するため、Algol 68)で変更されました。これにより、不正行為のないソリューションが可能になります(プログラムは解析ツリーなどを調べる必要がありません。また、ここにある他のほとんどすべてのソリューションとは異なり、ネストされた呼び出しがFFI)。
私はまた、言語のいくつかの癖を自慢することを決めました。(特に、変数名には空白を含めることができます。アンダースコアを含めることができないため、これは読みやすくするのにかなり役立ちます。コメントインジケーターがcomment
ほとんどの構文エンコーディングのリテラルワードであるという事実も気に入っています。Algol68は、これを略して扱いにくいと感じました。コメントと¢
代替として紹介します。コメント本文を囲む引用符は通常は必要ありません。わかりやすくするため、およびセミコロンを入力したときにコメントが誤って終了しないようにするために、引用符を追加します。)言語の幅広い概念が本当に好きです(詳細でない場合)、しかしそれは私がPPCGでそれを使用することはめったにないほど冗長です。
Algol 60がインスピレーションを得た言語と異なる主な方法(Algol 68、間接的にC、Javaなど。K&R Cを知っている人は、おそらく関数のこの構文を認識するでしょう)は、関数の引数が少し似ていることです。独自の小さなラムダ。たとえば、5
5という数値だけの関数に引数を指定した場合、引数x+1
を指定すると、指定したとおりx
の結果が得x
られます。つまり、プラス1の結果ではなく、「プラス1」の概念になります。場合ということですx
変更は、その後、評価しようとし、当該関数の引数が表示されます新しいのの値をx
。関数の引数が関数の内部で評価されない場合、関数の外部でも評価されません。同様に、それが関数内で複数回評価される場合、それは毎回別々に評価されます(これは最適化できないと仮定します)。これは、たとえば、関数内で、if
または関数内で機能をキャプチャすることなどが可能であることを意味しwhile
ます。
このプログラムでは、関数の呼び出しがその関数の引数に現れた場合、その関数は再帰的に実行されるという事実を利用しています(引数は、関数が評価するポイントで正確に評価されるため) 、以前も後もない。これは必ずしも関数本体の内部にある必要がある)。これにより、関数が再帰的に実行されているかどうかを検出するという問題が軽減され、はるかに簡単になります。必要なのは、再帰呼び出しがあるかどうかを検出するスレッドローカル変数(さらに、この場合、別の方法で情報をやり取りするための別の呼び出し)です。静的変数(つまり、own
)目的のため、Algol 60はシングルスレッドです。その後に行う必要があるのは、すべてを元の状態に戻すことです。これにより、関数が複数回呼び出された場合に正しく機能します(PPCGルールで必要な場合)。
この関数は、現時点では内部呼び出しから望ましい値を返しません(少なくとも、自分自身を数えるのではなく、引数のみで自己呼び出しを探す必要があると仮定した場合)。その作業を行うことは、同じ一般的な原則を使用するとかなり簡単ですが、より複雑であり、機能の動作がわかりにくくなります。それが質問に準拠するために必要であると思われる場合、変更することはそれほど難しくないはずです。
print(func(), func(func()))
必要がありますか、それとも関数が定義された直後に関数へのトップレベルの呼び出ししかありませんか?