“名前で渡す”とはそして、それはどのように正確に機能しますか?
-
10-07-2019 - |
質問
ウィキペディアを確認し、グーグルで検索しましたが、ALGOL 60で名前によるパスがどのように機能するかについてはまだ気にしません。
解決
Pass-By-Nameパラメーターの受け渡しで適切な説明を見つけました。 。基本的に、関数の本文は、実際のパラメーターを関数の本文にテキストで置き換えた後、呼び出し時に解釈されます。この意味で、評価方法はCプリプロセッサマクロの評価方法と似ています。
実際のパラメーターを関数本体に代入することにより、関数本体は指定されたパラメーターの読み取りと書き込みの両方を行うことができます。この意味で、評価方法は参照渡しに似ています。違いは、名前渡しの場合、パラメーターは関数内で評価されるため、 a [i]
などのパラメーターはの現在の値に依存することです。関数が呼び出される前の
。 a [i]
の値を参照するのではなく、関数内のi
上記でリンクしたページには、名前渡しが便利で危険な場所の例がいくつかあります。名前渡しによって可能になった手法は、参照渡しやラムダ関数など、他のより安全な手法によって今日ではほぼ置き換えられています。
他のヒント
ALGOL 60で名前による呼び出しを意味すると仮定しています。
名前による呼び出しは、渡されたパラメーターの値を変更できるという点で、参照による呼び出しに似ています。参照による呼び出しとは異なり、プロシージャが呼び出される前にパラメーターが 評価されず、代わりに遅延評価されます。つまり、パラメータが実際に使用される場合にのみ評価されます。
たとえば、プロシージャ f(x、y)
があり、それを i
および i / 2
に渡すと仮定します。ここで i
は最初は 10
に等しいです。 f
が x
を 42
に設定してから y
を評価すると、値 21
(一方、参照による呼び出しまたは値による呼び出しでは、まだ 5
が表示されます)。これは、式 i / 2
は、 y
が評価されるまで評価されないためです。
多くの点で、これはパラメーターのリテラルテキスト置換のように動作するように見えます(名前の競合を避けるために名前を変更します)。ただし、実際には、これは「サンク」を使用して実装されます。 (基本的にクロージャ)渡された式に対して。
Jensenのデバイスに関するWikipediaの記事には、名前による呼び出しの興味深い使用例が示されています。 。それらの1つを次に示します。
real procedure Sum(k, l, u, ak) value l, u; integer k, l, u; real ak; comment k and ak are passed by name; begin real s; s := 0; for k := l step 1 until u do s := s + ak; Sum := s end;
手順では、インデックス変数
k
および合計項ak
は 名前で渡されます。名前で呼び出すと、プロシージャは値を変更できます forループの実行中のインデックス変数の値。名前で呼び出す また、ak
引数は、次の各反復中に再評価されます。 ループ。通常、ak
は変化に依存します(副作用)k
。たとえば、実数の最初の100項の合計を計算するコード 配列
V []
は次のようになります。Sum(i, 1, 100, V[i]).
将来の方へ:
プログラミング言語の概念 ジョン・C・ミッチェルも役に立ちました。
パスバイネーム。おそらく最も奇妙な 振り返ってみると、Algol 60の機能は 名前によるパスの使用。に pass-by-name、の結果 手続き呼び出しは、 仮パラメータは プロシージャの本体。このルール プロシージャの結果を定義するため プロシージャをコピーして呼び出し、 仮パラメータの代替 Algol 60コピールールと呼ばれます。 コピールールは 純粋な機能プログラム、として βラムダの減少 計算、サイドとの相互作用 仮パラメータへの影響は 少し奇妙です。ここに例があります 参照されている手法を示すプログラム ジェンセンのデバイスとして: 式とそれに含まれる変数 プロシージャに 1つのパラメーターを使用して、 他が参照する場所:
begin integer i; integer procedure sum(i, j); integer i, j; comment parameters passed by name; begin integer sm; sm := 0; for i := 1 step 1 until 100 do sm := sm + j; sum := sm end; print(sum(i, i*10 )) end
このプログラムでは、手順 sum(i、j)は、jの値をiとして加算します 1から100になります。 コードを使用すると、 手順は意味がありません iを変更すると、 jの値。それ以外の場合、手順 100 * jを計算するだけです。通話中 ここに示すsum(i、i * 10)、forループ プロシージャの本文の合計 iが1から1になるときのi * 10の値 100。
実際には、名前で呼ぶのは歴史的な好奇心だけではありません。 Windowsバッチファイル(および他の無数のスクリプト言語)で名前で呼び出すことができます。それがどのように機能するか、そしてそれをプログラミングで効果的に使用する方法を知ることは、問題に対するきちんとした解決策を開くことができます。後で展開するために文字列を渡すだけですが、名前による呼び出しと同様の効果を持つように操作できます。
call :assign x 1
exit /b
:assign
setlocal enabledelayedexpansion
(endlocal
:: Argument 1 is the name of the variable
set %1=%2
)
exit /b
Flatlanderには、Scalaでの動作の例がありますこちら。 while :
を実装するとします。def mywhile(condition: => Boolean)(body: => Unit): Unit = if (condition) { body mywhile(condition)(body) }
これは次のように呼び出すことができます。
var i = 0 mywhile (i < 10) { println(i) i += 1 }
ScalaはAlgol 60ではありませんが、おそらく光を放ちます。
&quot; name&quot;を渡すことができます。同時に更新およびアクセスできる変数のシンボリック形式。例として、int型の変数xを3倍にしたいとします:
start double(x);
real x;
begin
x : = x * 3
end;
ALGOLは数学アルゴリズム用に設計されました。名前による呼び出しの例として、加算関数が好きです。
申し訳ありませんが、私のALGOLは少しさびているので、構文がおそらく正しくありません。
.FUNCTION SUM(var,from,to,function)
.BEGIN
.REAL sum =0;
.FOR var = from .TO to .DO sum = function;
return sum;
.END
次のようにsumを使用できます
Y = sum(x,1,4,sum(y,3,8,x+y));
上記では、内側のsum(y、3,8、x + y)は名前のない関数を生成して、外側のsum呼び出しに渡します。変数xおよびyは、値ではなく名前で渡されます。変数の場合、名前による呼び出しは、Cのアドレス参照による呼び出しと同等です。再帰が関係する場合、少し混乱します。
借金はALGOLマシンを作りました。彼らは3フラグビットで48ビットワードメモリを持っていました。フラグビットは、ALGOLという名前でcalを実装しました。これはスタックマシンであったため、関数がスタックにロードされると、fagという名前の呼び出しによって呼び出されます。式が引数として使用された場合、コンパイラは名前のない関数を生成します。変数は、単純な間接参照になります。関数への書き込み中にエラーが発生しました。
クラブに遅れて参加することは知っていますが、これは必ずしも答えではありませんが、少し明確にするために役立つことが1つあります。 Algolの名前によるパスは、C ++プリプロセッサディレクティブ(具体的にはマクロ)がコンパイル時に関数/変数の名前を実際のコードに置き換えるときと同様のプロセスだと常に考えてきました。名前渡しは、基本的に仮パラメータの名前を実際のパラメータに置き換えて実行します。 Algolで書いたことはありませんが、名前渡しはC ++の参照渡しと同じ結果になると聞きました。