関数の名前に割り当てることによって設定される戻り値はどの言語ですか?
このStackOverflowの質問では、元のコードが関数名を変数として使用するという間違いを犯し、それに戻り値を割り当てました。コメンターは、彼がかつて、これはあなたが関数から値を戻した方法だったの言語を使用したことを述べました。コメントには、「関数の戻り値を関数の名前に割り当てる必要のある言語を使用したことがあることは知っています。それは非常に古く、時代遅れで、どの言語であったかさえ思い出せません。」
それは私にも馴染みがあるように聞こえますが、それがどの言語であったかも思い出せません。
誰かが私たちよりも良い記憶を持っていて、それがどの言語であるかを教えてくれますか?
回答
パスカルはこれをします、私は他の人を知りません。練習が他のワース言語で前進するかどうかわからない。
Visual Basicファミリの言語は、まさにこれを実行します。これには、VBScript、VBA、VisualBasicなどが含まれます。これらはQBASICから「機能」を継承していると思います。例えば
Public Function AddTwo(something as Integer)
AddTwo = something + 2
End Function
確かにFortran:
PROGRAM TRIANG
WRITE(UNIT=*,FMT=*)'Enter lengths of three sides:'
READ(UNIT=*,FMT=*) SIDEA, SIDEB, SIDEC
WRITE(UNIT=*,FMT=*)'Area is ', AREA3(SIDEA,SIDEB,SIDEC)
END
FUNCTION AREA3(A, B, C)
*Computes the area of a triangle from lengths of sides
S = (A + B + C)/2.0
AREA3 = SQRT(S * (S-A) * (S-B) * (S-C))
END
(Clive G. PageのProfessionalProgrammer's Guide to Fortran77から)。
また、Fortran ANSI X 3.9 1966 Fortran66規格でもそのように定義されています。
私が見つけることができる最も初期のそのような言語は、FORTRANIIとALGOL58であり、どちらも1958年に同じ年に発行されました。ただし、元のFORTRAN(1956)も間違いなく含めることができます。
FORTRANの場合、関数をカバーするマニュアルの章の最初のページに次の例が含まれています(p.27)。
FUNCTION AVRG (ALIST, N)
DIMENSION ALIST (500)
SUM = ALIST (1)
DO 10 I=2, N
SUM = SUM + ALIST (I)
AVRG = SUM / FLOATF (N)
RETURN
END (2, 2, 2, 2, 2)
FORTRAN IIには、前の関数から継承された別の関数構文(p。10)である1行の関数定義も含まれています。
FIRSTF(X) = A*X + B
前者の構文が後者の自然な拡張であり、数学的な使用法に由来することを理解するのは難しいことではありません。
ALGOL 58は、FORTRANと同様に、両方の単一行の「関数」を定義します。
関数宣言は、その変数の特定の関数であることが与えられた式を宣言する。これにより、宣言は、この関数が式に現れるときはいつでも、関数(関数を参照)に値を割り当てるための計算規則を(特定の単純な関数に対して)与えます。
形式:Δ〜I n(I、I、〜、I):= Eここで、Iは識別子であり、Eは、その構成要素の中で、括弧内に表示される識別子によって名前が付けられた単純な変数を含むことができる式です。
および「procedures」。これは、今日の関数の定義に相当します(少なくとも、命令型/手続き型プログラミング言語では)。戻り値は次のように表示されます(p.19)。
見出しにリストされている単一の出力プロシージャI(P i)ごとに、代入ステートメント「I:= E」によってプロシージャ内に値を割り当てる必要があります。ここで、Iはそのプロシージャに名前を付ける識別子です。
これらの構文は、後にBASICの一部の方言(DEF FN
以降の形式FUNCTION
)とALGOLの子孫Pascalによって採用されました。BorlandのPascalコンパイラでは、Result
Delphi 1.0で変数が導入される前は、関数名への割り当てのみがサポートされていました。
言及されたコメンターが覚えていたのはおそらくパスカルです。一部の大学はまだプログラミングを教えており、通常、Object Pascalのような最新の拡張方言ではなく、元の標準的な種類に固執しています。(これは実際には質問の一部ではありませんが、StackOverflowの質問者の誤解もそこから来たと思います。)
TL; DR:
80年代初頭にかなり人気があり、80年代から90年代にかけて大学のコースで使用され、その後もいくつかのフェローシップがあったため、おそらく覚えているのはPASCALだと思います。特にDelphiです。
いくつかの歴史
基本的な考え方は、関数名はすでに予約されているだけではないので、何か別のものを考え出す必要はなく、それを使用することは、これが結果であることを明確に示しています。また、呼び出し規約内で専用のデータ項目を割り当てることができるため、コンパイラの設計が簡素化されます。
基本的に、FORTRANとALGOLの2つの遺産があります。
彼らの子孫のいくつかは両方のためにそれを維持しました
- FORTRANおよび
- ALGOLのPascalとModula。
ALGOLのフォローアップのように、他の人はそれを落としました
return()
構文を導入したBCPL、
これは、CがBCPLから取得したため、今日では非常に一般的です。
言語のアイデアは、遺伝子がホスト間をジャンプするようなものです。たとえば、ADAは、多くの点でALGOL / PASCALの孫であり、return
要素の使用にも目を向けました。
おじいちゃんFORTRANは、何年にもわたって、関数の結果を返す方法を変えてきました。
- 元々、関数の結果は関数の識別子に割り当てられていました
- FORTRAN 90では、関数ヘッドでの戻り名の明示的な定義が導入されました。
これは本質的に単なる構文糖衣ですが、スタイルの変更が特徴です。適用された理由は、再帰構造を使用Foo = Foo(x-1)
すると、のように奇妙に見えるというものでした。しかし、それは解釈次第だと思います。
ここでも興味深いのは、1958年のFORTRAN IIがRETURN
手続き型プログラミングを追加するためのステートメントを導入したことですが、その使用法は単に実行を呼び出し元に返すことであり、戻り値は個別に設定する必要がありました。
Fortranは、この構文を使用しており、機能を備えた初期のバージョンから、Fortran2008以降まで使用されています。
ただし、Fortran 2008には、関数値を返すために使用される別の変数名を宣言できる(さらに紛らわしい?)オプションがあります。例えば
function xyz(argument) result(answer)
...
answer = 42
...
end function xyz
古いスタイルの代わりに
...
xyz = 42
...
1つはAlgol60。
これは、Algorithmic Language Algol60に関する改訂レポートの関連する単語です。
5.4.4。関数指定子の値。
プロシージャ宣言で関数指定子の値を定義するには、プロシージャ宣言の本文内で、左側にプロシージャ識別子を持つ1つ以上の明示的な代入ステートメントを指定する必要があります。これらの少なくとも1つを実行する必要があり、プロシージャ識別子に関連付けられた型は、プロシージャ宣言の最初のシンボルとして型宣言子を出現させることによって宣言する必要があります。そのように割り当てられた最後の値は、関数指定子が発生する式の評価を続行するために使用されます。
割り当てステートメントの左側以外のプロシージャの本体内でプロシージャ識別子が出現する場合は、プロシージャがアクティブ化されていることを示します。
最後の文は重要です。これは、プロシージャ(関数)型の名前が、プロシージャ(関数)本体内の変数と同じように扱われないことを示しています。むしろ、特別な場合があるのは割り当てだけです。
Algol 60では、引数をとらない関数の呼び出しの後には、空の括弧が続きません。つまり、n := read
ではありませんn := read()
。
最後の文は、言語に再帰的な手順を取り入れた文としても有名です。しかし、それはこの答えと密接な関係はありません。
BASICは、一部の方言が関数名への代入を使用して戻り値を提供する関数を備えた別の言語です。初期の方言は、Fortranの単一行関数に似ていました。
DEF FND(x) = x*x
しかし、後の方言では、Fortranの複数行関数と同様に、より複雑なバリアントが許可されていました。
DEF FNPeekWord& (A&)
FNPeekWord& = PEEK(A&) + 256& * PEEK(A& + 1)
END DEF
MATLAB / Octaveもこれを行います。
1984年からです。他のいくつかほど古くはありません。
もともとは高レベルのツールとして考えられていたので、おそらくFortranを模倣していました。LinpackやEispackなどのFortranライブラリに加えて。
SNOBOL4がこれを行ったと思います。 http://berstis.com/greenbook.pdf
以下は、数値の階乗を計算するための関数の定義と使用の例です。
DEFINE('FACT(N)') :(SKIPFCN) * Set value to 1 FACT FACT = 1 * Return 1 if N<2 * Return N*((N-1)!) with recursive call FACT = GT(N,1) FACT(N - 1) * N :(RETURN) SKIPFCN OUTPUT = '5 factorial is ' FACT(5)
http://berstis.com/s4ref/prim3e.htm
Verilog(1995/2001)も、暗黙の変数への代入によって返されます。SystemVerilogは「return」ステートメントを追加しましたが、従来の割り当ては引き続き使用できます。
Haskell(1990年から)もこれを行います:
doubleMe x = x + x
doubleMe
1つのパラメーターの関数を定義し、x
それに関数本体x+x
を割り当てます。すばらしいLearn You A Haskell For GreatGoodを参照してください。
パスカルは私が個人的に使ったものです。Common Lispはちょっとソートしますが、実際にはそうではありません。戻り値はほとんど常に暗黙的です(つまり、すべてのステートメントに値があり、ブロックの最後の値がブロックの戻り値です)。明示的なreturnステートメントですが、値を返す必要があり、暗黙的な方法を使用できない場合は、次のようにRETURN-FROM
[*]ステートメントを使用します(return-from function-name value)
。
[*]RETURN
ステートメントもありますが、これはの省略形であり(return-from nil value)
、実行された関数の値を作成する効果はありませんVALUE
。これは、Cとその子孫から来る初心者にとって大きな落とし穴です。