W jakim języku (językach) jest ustawiana wartość zwracana przez przypisanie jej do nazwy funkcji?

Jan 18 2021

W tym pytaniu o przepełnienie stosu oryginalny kod popełnił błąd, używając nazwy funkcji jako zmiennej i przypisał jej wartość zwracaną. Komentator wspomniał, że kiedyś, gdzie język ten był sposób zwrócił wartość z funkcji. W komentarzu czytamy: „Wiem, że kiedyś użyłem języka, w którym wartość zwracana funkcji musiała być przypisana nazwie funkcji. Jest tak stara i przestarzała, że ​​nawet nie pamiętam, który to był język”.

To też brzmi znajomo, ale nie pamiętam też, jaki to był język.

Czy ktoś ma lepszą pamięć niż my i może nam powiedzieć, jaki to język?

Odpowiedzi

50 WillHartung Jan 18 2021 at 22:45

Pascal to robi, ja nie znam innych. Nie wiem, czy praktyka posuwa się naprzód z innymi językami Wirtha.

50 OmarL Jan 18 2021 at 23:14

Języki z rodziny Visual Basic robią dokładnie to. Obejmuje to VBScript, VBA, Visual Basic i wcześniejsze. Uważam, że dziedziczą one „funkcję” po QBASIC-u. Na przykład

Public Function AddTwo(something as Integer)
    AddTwo = something + 2
End Function
29 scruss Jan 18 2021 at 23:03

Fortran na pewno:

      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

(z podręcznika programisty Clive'a G. Page'a do Fortran77 ).

Jest to również zdefiniowane w ten sposób w standardzie Fortran ANSI X 3.9 1966 Fortran 66 .

22 user3840170 Jan 18 2021 at 23:54

Najwcześniejszymi takimi językami, jakie mogę znaleźć, są FORTRAN II i ALGOL 58, oba opublikowane w tym samym roku 1958; chociaż oryginalny FORTRAN (1956) może również zostać uwzględniony.

W przypadku FORTRAN, pierwsza strona rozdziału instrukcji opisującego funkcje zawiera następujący przykład (s.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 zawiera również inną składnię funkcji (s. 10), definicję funkcji jednowierszowej, odziedziczoną po jej poprzedniku:

FIRSTF(X) = A*X + B

Nietrudno dostrzec, że pierwsza składnia jest naturalnym rozszerzeniem drugiej, z kolei wywodzącą się z użycia matematycznego.

ALGOL 58 , podobnie jak FORTRAN, definiuje obie jednowierszowe `` funkcje '':

Funkcja deklaracja deklaruje dany wyraz być funkcją niektórych jego zmiennych. W związku z tym deklaracja podaje (dla niektórych funkcji prostych) regułę obliczania przypisywania wartości do funkcji (por. Funkcje ) za każdym razem, gdy funkcja ta występuje w wyrażeniu.

Postać: Δ ~ I n (I, I, ~, I): = E, gdzie I to identyfikatory, a E to wyrażenie, które wśród swoich składników może zawierać proste zmienne nazwane przez identyfikatory pojawiające się w nawiasach.

oraz „procedury”, odpowiednik dzisiejszej definicji funkcji (przynajmniej w imperatywnych / proceduralnych językach programowania). Zwracana wartość jest oznaczona w następujący sposób (s. 19):

Każdej pojedynczej procedurze wyjściowej I (P i ) wymienionej w nagłówku należy przypisać wartość w ramach procedury za pomocą instrukcji przypisania „I: = E”, gdzie I jest identyfikatorem określającym tę procedurę.

Te składnie zostały później przejęte przez niektóre dialekty języka BASIC (w postaci DEF FNi późniejszej FUNCTION) i potomka ALGOL-a Pascala: w kompilatorach Borlanda Pascal przypisanie do nazwy funkcji było jedyną obsługiwaną składnią przed wprowadzeniem Resultzmiennej w Delphi 1.0.

Prawdopodobnie to Pascal zapamiętał wspomniany komentator; niektóre uniwersytety nadal uczą w nim programowania i zwykle trzymają się oryginalnej, standardowej odmiany, zamiast nowoczesnych rozszerzonych dialektów, takich jak Object Pascal. (To nie jest tak naprawdę część pytania, ale zakładam, że nieporozumienie pytającego StackOverflow również pochodzi z tego).

17 Raffzahn Jan 19 2021 at 00:28

TL; DR:

Powiedziałbym, że najprawdopodobniej jest to PASCAL, który pamiętasz, ponieważ był dość popularny we wczesnych latach 80-tych, używany na kursach uniwersyteckich od lat 80-tych do lat 90-tych, a potem nadal miał tam trochę stypendium, zwłaszcza Delphi.


Trochę historii

Podstawową ideą jest to, że nazwa funkcji nie tylko jest już zarezerwowana, więc nie trzeba wymyślać niczego innego, a używanie jej jest jasnym stwierdzeniem, że to jest wynik. Upraszcza również projekt kompilatora, ponieważ dedykowany element danych może być przydzielony w ramach konwencji wywoływania.

Istnieją zasadniczo dwie linie dziedzictwa, FORTRAN i ALGOL.

Dla obojga ich potomków zachował to, jak

  • niektóre podstawowe warianty FORTRAN i
  • Pascal i Modula firmy ALGOL.

Inni porzucili to, jak kontynuacja ALGOL

  • BCPL, który wprowadził return()składnię,

co jest dziś dość powszechne, ponieważ C wziął to z BCPL.

Idee językowe są jak geny przeskakujące między gospodarzami. Na przykład ADA, pod wieloma względami wnuk ALGOL / PASCAL, również zwrócił się do używania returnelementu.

Dziadek FORTRAN przez lata zmieniał sposób zwracania wyników funkcji.

  • Pierwotnie wynik funkcji był przypisany do identyfikatora funkcji
  • z FORTRAN 90 wprowadzono jawną definicję nazwy zwracanej w nagłówku funkcji.

Chociaż jest to zasadniczo tylko cukier syntaktyczny, zawiera zmianę stylu. Zastosowano rozumowanie, że w przypadku konstrukcji rekurencyjnych wyglądałoby Foo = Foo(x-1)to dziwnie. Ale myślę, że to zależy od interpretacji.

Interesujące jest również to, że FORTRAN II z 1958 r. Wprowadził RETURNinstrukcję, starając się dodać programowanie proceduralne, ale jego użycie polegało po prostu na zwróceniu wykonania wywołującemu, wartość zwracana musiała być ustawiona osobno.

12 alephzero Jan 18 2021 at 23:02

Fortran używał tej składni, od najwcześniejszej wersji, która w ogóle miała funkcje, aż do Fortran 2008 i później.

Jednak Fortran 2008 ma (jeszcze bardziej mylącą?) Opcję, w której można zadeklarować inną nazwę zmiennej, która jest używana do zwracania wartości funkcji! Na przykład

function xyz(argument) result(answer)
...
answer = 42
...
end function xyz

zamiast starego stylu

...
xyz = 42
...
9 another-dave Jan 19 2021 at 01:02

Algol 60 za jednego.

Oto odpowiednie słowa z poprawionego raportu o języku algorytmicznym Algol 60 .

5.4.4. Wartości wyznaczników funkcji.

Aby deklaracja procedury definiowała wartość desygnatora funkcji, w treści deklaracji procedury musi wystąpić jedna lub więcej jawnych instrukcji przypisania z identyfikatorem procedury w lewej części; co najmniej jeden z nich musi zostać wykonany, a typ skojarzony z identyfikatorem procedury musi zostać zadeklarowany poprzez pojawienie się deklaratora typu jako pierwszy symbol deklaracji procedury. Ostatnia tak przypisana wartość jest używana do kontynuowania oceny wyrażenia, w którym występuje desygnator funkcji.

Wystąpienie identyfikatora procedury w treści procedury, inne niż w lewej części zestawienia przypisania, oznacza aktywację procedury.

Ostatnie zdanie jest znaczące - pokazuje, że nazwa procedury (funkcji) typu nie jest traktowana „tak jak” zmienna w treści procedury (funkcji); raczej jest to tylko przypisanie, które jest oznaczone specjalną wielkością.

W Algolu 60 po wywołaniu funkcji, która nie przyjmuje argumentów, nie występują puste nawiasy: tak, n := reada nie n := read().

Ostatnie zdanie jest również znane jako zdanie, które otrzymało w języku procedury rekurencyjne. Ale to nie jest związane z tą odpowiedzią.

6 StephenKitt Jan 18 2021 at 23:03

BASIC to inny język z funkcjami, w których niektóre dialekty używają przypisania do nazwy funkcji, aby zapewnić zwracaną wartość. Najwcześniejsze dialekty były podobne do funkcji jednowierszowych języka Fortran:

DEF FND(x) = x*x

Ale późniejsze dialekty pozwoliły na bardziej złożone warianty, podobne do funkcji wieloliniowych Fortran :

DEF FNPeekWord& (A&)
  FNPeekWord& = PEEK(A&) + 256& * PEEK(A& + 1)
END DEF
5 LyndonWhite Jan 19 2021 at 20:38

MATLAB / Octave również to robi.

Pochodzi z 1984 roku; nie tak stary jak niektóre inne.

Prawdopodobnie naśladował Fortran, ponieważ pierwotnie był pomyślany jako narzędzie wysokiego poziomu. Oprócz bibliotek Fortran, takich jak Linpack i Eispack.

5 chasly-supportsMonica Jan 19 2021 at 21:29

Uważam, że SNOBOL4 to zrobił. http://berstis.com/greenbook.pdf

Poniżej znajduje się przykład definicji i użycia funkcji do obliczania silni liczb:

   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

4 d3jones Jan 19 2021 at 07:12

Verilog (1995/2001) zwraca również przez przypisanie do niejawnej zmiennej. SystemVerilog dodał instrukcję „return”, ale klasyczne przypisanie jest nadal dostępne.

1 arne Jan 21 2021 at 03:02

Haskell (od 1990) też to robi:

doubleMe x = x + x  

definiuje funkcję doubleMejednego parametru xi przypisuje do niego treść funkcji x+x, zobacz świetny Learn You A Haskell For Great Good

mathrick Jan 19 2021 at 13:08

Pascal to ten, z którego osobiście korzystałem, aby to zrobić. Typowy Lisp rodzaj-sorta-ale-tak naprawdę to robi, ponieważ zwracane wartości są prawie zawsze niejawne (tj. Każda instrukcja ma wartość, a ostatnia wartość w bloku jest wartością zwracaną przez blok), więc bardzo rzadko widzisz wyraźne oświadczenie powrót, ale gdy trzeba zwrócić wartość i nie można używać niejawny sposób, sposób na to jest za pomocą RETURN-FROM[*] oświadczenie, tak: (return-from function-name value).

[*] Istnieje również RETURNinstrukcja, ale jest ona skrótem (return-from nil value)i nie będzie miała wpływu na tworzenie VALUEwartości funkcji, w której została wykonana. To wielka pułapka dla nowicjuszy pochodzących z C i jego potomków.