Jaka jest różnica między programowaniem proceduralnym a programowaniem funkcjonalnym? [Zamknięte]


247

Czytałem artykuły z Wikipedii dotyczące programowania proceduralnego i programowania funkcjonalnego , ale nadal jestem nieco zdezorientowany. Czy ktoś mógłby sprowadzić to do rdzenia?


Wikipedia sugeruje, że FP jest podzbiorem (tj. Zawsze) programowania deklaratywnego, ale to nie jest prawda i łączy w sobie taksonomię własności intelektualnej z DP .
Shelby Moore III

Odpowiedzi:


151

Język funkcjonalny (najlepiej) pozwala napisać funkcję matematyczną, tj. Funkcję, która przyjmuje n argumentów i zwraca wartość. Jeśli program jest wykonywany, funkcja ta jest logicznie oceniana w razie potrzeby. 1

Język proceduralny, z drugiej strony, wykonuje szereg kolejnych etapów. (Istnieje sposób na przekształcenie logiki sekwencyjnej w logikę funkcjonalną zwaną stylem przekazywania kontynuacji .)

W rezultacie czysto funkcjonalny program zawsze daje taką samą wartość dla danych wejściowych, a kolejność oceny nie jest dobrze zdefiniowana; co oznacza, że ​​niepewne wartości, takie jak dane wejściowe użytkownika lub wartości losowe, są trudne do modelowania w czysto funkcjonalnych językach.


1 Jak wszystko inne w tej odpowiedzi, jest to uogólnienie. Ta właściwość, oceniająca obliczenia, gdy wynik jest potrzebny, a nie sekwencyjnie tam, gdzie się go nazywa, jest znana jako „lenistwo”. Nie wszystkie języki funkcjonalne są tak naprawdę leniwe, ani lenistwo nie ogranicza się do programowania funkcjonalnego. Podany tutaj opis stanowi raczej „mentalną strukturę” do myślenia o różnych stylach programowania, które nie są odrębnymi i przeciwnymi kategoriami, ale raczej płynnymi pomysłami.


9
Niepewne wartości, takie jak dane wprowadzane przez użytkownika lub wartości losowe, są trudne do modelowania w czysto funkcjonalnych językach, ale jest to rozwiązany problem. Zobacz monady.
Apocalisp

sekwencyjne etapy , w których program funkcjonalny byłby zagnieżdżony” oznacza zapewnienie rozdzielenia problemów przez podkreślenie składu funkcji , tj. oddzielenie zależności między podliczeniami obliczeń deterministycznych.
Shelby Moore III

wydaje się to niewłaściwe - procedury można również zagnieżdżać, procedury mogą mieć parametry
Hurda,

1
@Hurda Tak, mógłbym to lepiej sformułować. Chodzi o to, że programowanie proceduralne odbywa się krokowo w z góry określonej kolejności, podczas gdy programy funkcjonalne nie są wykonywane krok po kroku; raczej wartości są obliczane, kiedy są potrzebne. Jednak brak ogólnie uzgodnionej definicji terminologii programowania czyni takie uogólnienia prawie bezużytecznymi. Poprawiłem w tym względzie swoją odpowiedź.
Konrad Rudolph

97

Zasadniczo oba style są jak Yin i Yang. Jeden jest zorganizowany, a drugi chaotyczny. Są sytuacje, w których programowanie funkcjonalne jest oczywistym wyborem, a inne sytuacje, w których programowanie proceduralne jest lepszym wyborem. Właśnie dlatego istnieją co najmniej dwa języki, które niedawno wydały nową wersję, która obejmuje oba style programowania. ( Perl 6 i D 2 )

Proceduralny:

  • Wyjście procedury nie zawsze ma bezpośrednią korelację z danymi wejściowymi.
  • Wszystko odbywa się w określonej kolejności.
  • Wykonanie rutyny może mieć skutki uboczne.
  • Zazwyczaj kładzie nacisk na wdrażanie rozwiązań w sposób liniowy.

Perl 6

sub factorial ( UInt:D $n is copy ) returns UInt {

  # modify "outside" state
  state $call-count++;
  # in this case it is rather pointless as
  # it can't even be accessed from outside

  my $result = 1;

  loop ( ; $n > 0 ; $n-- ){

    $result *= $n;

  }

  return $result;
}

D 2

int factorial( int n ){

  int result = 1;

  for( ; n > 0 ; n-- ){
    result *= n;
  }

  return result;
}

Funkcjonalny:

  • Często rekurencyjne.
  • Zawsze zwraca to samo wyjście dla danego wejścia.
  • Kolejność oceny jest zwykle nieokreślona.
  • Musi być bezpaństwowcem. tzn. żadna operacja nie może mieć skutków ubocznych.
  • Dobre dopasowanie do wykonywania równoległego
  • Zazwyczaj podkreśla podejście dziel i zwyciężaj.
  • Może mieć funkcję Lazy Evaluation.

Haskell

(skopiowane z Wikipedii );

fac :: Integer -> Integer

fac 0 = 1
fac n | n > 0 = n * fac (n-1)

lub w jednej linii:

fac n = if n > 0 then n * fac (n-1) else 1

Perl 6

proto sub factorial ( UInt:D $n ) returns UInt {*}

multi sub factorial (  0 ) { 1 }
multi sub factorial ( $n ) { $n * samewith $n-1 } # { $n * factorial $n-1 }

D 2

pure int factorial( invariant int n ){
  if( n <= 1 ){
    return 1;
  }else{
    return n * factorial( n-1 );
  }
}

Dygresja:

Faktyczny jest tak naprawdę częstym przykładem pokazującym, jak łatwo jest tworzyć nowe operatory w Perlu 6 w taki sam sposób, jak tworzy się podprogram. Ta funkcja jest tak wbudowana w Perl 6, że większość operatorów w implementacji Rakudo jest zdefiniowana w ten sposób. Umożliwia także dodawanie własnych wielu kandydatów do istniejących operatorów.

sub postfix:< ! > ( UInt:D $n --> UInt )
  is tighter(&infix:<*>)
  { [*] 2 .. $n }

say 5!; # 120␤

W tym przykładzie pokazano również tworzenie zakresu ( 2..$n) i metaoperator redukcji listy ( [ OPERATOR ] LIST) w połączeniu z operatorem zwielokrotnienia liczby . ( *)
Pokazuje również, że można wstawić --> UIntpodpis zamiast returns UIntpo nim.

(Możesz uciec od rozpoczęcia zakresu, 2ponieważ powielony „operator” powróci, 1gdy zostanie wywołany bez żadnych argumentów)


Cześć, czy możesz podać przykład 2 poniższych punktów dla „Proceduralnego”, biorąc pod uwagę przykład implementacji czynnikowej w Perlu 6. 1) Wyjście procedury nie zawsze ma bezpośrednią korelację z danymi wejściowymi. 2) Wykonanie rutyny może mieć skutki uboczne.
Naga Kiran

sub postfix:<!> ($n) { [*] 1..$n }
Brad Gilbert,

@BradGilbert- No operation can have side effectsCzy możesz to rozwinąć?
kushalvm

2
Prawdopodobnie najlepsza odpowiedź, jaką kiedykolwiek znalazłem ... I przeprowadziłem badania dotyczące tych poszczególnych punktów ... które naprawdę mi pomogły! :)
Navaneeth

1
@AkashBisariya sub foo( $a, $b ){ ($a,$b).pick }← nie zawsze zwraca to samo wyjście dla tego samego wejścia, podczas gdy następującesub foo( $a, $b ){ $a + $b }
Brad Gilbert

70

Nigdy nie widziałem tej definicji podanej gdzie indziej, ale myślę, że dość dobrze podsumowuje podane tutaj różnice:

Programowanie funkcjonalne koncentruje się na wyrażeniach

Programowanie proceduralne koncentruje się na stwierdzeniach

Wyrażenia mają wartości. Program funkcjonalny to wyrażenie, którego wartością jest sekwencja instrukcji do wykonania przez komputer.

Instrukcje nie mają wartości i zamiast tego modyfikują stan niektórych maszyn koncepcyjnych.

W czysto funkcjonalnym języku nie byłoby instrukcji, w tym sensie, że nie ma sposobu na manipulowanie stanem (mogą nadal mieć konstrukcję składniową o nazwie „instrukcja”, ale gdyby nie manipulowała stanem, nie nazwałbym tego stwierdzeniem w tym sensie ). W czysto proceduralnym języku nie byłoby wyrażeń, wszystko byłoby instrukcją, która manipuluje stanem maszyny.

Haskell byłby przykładem czysto funkcjonalnego języka, ponieważ nie ma możliwości manipulowania stanem. Kod maszynowy byłby przykładem języka czysto proceduralnego, ponieważ wszystko w programie jest instrukcją, która manipuluje stanem rejestrów i pamięci maszyny.

Zagmatwane jest to, że zdecydowana większość języków programowania zawiera zarówno wyrażenia, jak i instrukcje, co pozwala mieszać paradygmaty. Języki można klasyfikować jako bardziej funkcjonalne lub proceduralne na podstawie tego, na ile zachęcają do używania wyrażeń a wyrażeń.

Na przykład C byłby bardziej funkcjonalny niż COBOL, ponieważ wywołanie funkcji jest wyrażeniem, podczas gdy wywołanie podprogramu w języku COBOL jest instrukcją (która manipuluje stanm wspólnych zmiennych i nie zwraca wartości). Python byłby bardziej funkcjonalny niż C, ponieważ pozwala wyrazić logikę warunkową jako wyrażenie przy użyciu oceny zwarcia (test && path1 || path2 w przeciwieństwie do instrukcji if). Schemat byłby bardziej funkcjonalny niż Python, ponieważ wszystko w schemacie jest wyrażeniem.

Nadal możesz pisać w funkcjonalnym stylu w języku, który zachęca do paradygmatu proceduralnego i odwrotnie. Po prostu trudniej i / lub bardziej niezręcznie jest pisać w paradygmacie, który nie jest zachęcany przez język.


2
Najlepsze i najbardziej zwięzłe wyjaśnienie, jakie widziałem w sieci, brawo!
tommed

47

W informatyce programowanie funkcjonalne jest paradygmatem programowania, który traktuje obliczenia jako ocenę funkcji matematycznych i unika stanu i zmiennych danych. Podkreśla zastosowanie funkcji, w przeciwieństwie do proceduralnego stylu programowania, który podkreśla zmiany stanu.


4
Chociaż to wyjaśnienie najbardziej mi pomogło, wciąż nie rozumiem pojęcia programowania funkcjonalnego. Szukam stylu programowania, który nie zależy od odwoływania się do zewnętrznych obiektów w celu uruchomienia (wszystko, co funkcja musi uruchomić, powinno zostać przekazane jako parametr). Na przykład nigdy nie wstawiłbym GetUserContext()funkcji, kontekst użytkownika zostałby przekazany. Czy to funkcjonalne programowanie? Z góry dziękuję.
Matt Cashatt,

26

Uważam, że programowanie proceduralne / funkcjonalne / obiektywne dotyczy sposobu podejścia do problemu.

Pierwszy styl planuje wszystko krok po kroku i rozwiązuje problem, wdrażając jeden krok (procedurę) na raz. Z drugiej strony programowanie funkcjonalne kładłoby nacisk na podejście „dziel i rządź”, w którym problem jest podzielony na podproblem, następnie każdy podproblem jest rozwiązywany (tworzenie funkcji do rozwiązania tego podproblemu), a wyniki są łączone w celu utwórz odpowiedź na cały problem. Wreszcie, programowanie obiektywne naśladuje rzeczywisty świat poprzez stworzenie mini-świata wewnątrz komputera z wieloma obiektami, z których każdy ma (nieco) unikalne cechy i współdziała z innymi. Z tych interakcji wynikałby wynik.

Każdy styl programowania ma swoje zalety i wady. Dlatego robienie czegoś takiego jak „czyste programowanie” (tj. Czysto proceduralne - nikt nie robi tego, co jest dziwne - lub czysto funkcjonalne lub czysto obiektywne) jest bardzo trudne, jeśli nie niemożliwe, z wyjątkiem niektórych elementarnych problemów, szczególnie zaprojektowany w celu wykazania przewagi stylu programowania (stąd tych, którzy lubią czystość, nazywamy „weenie”: D).

Następnie, z tych stylów, mamy języki programowania, które zostały zaprojektowane tak, aby zoptymalizować je dla każdego stylu. Na przykład w Zgromadzeniu chodzi o procedury. Okej, większość wczesnych języków ma charakter proceduralny, nie tylko Asm, jak C, Pascal (i Fortran, słyszałem). Następnie wszyscy mamy znaną Javę w obiektywnej szkole (w rzeczywistości Java i C # są również w klasie zwanej „zorientowaną na pieniądze”, ale jest to przedmiotem kolejnej dyskusji). Również celem jest Smalltalk. W szkole funkcjonalnej mielibyśmy „prawie funkcjonalną” (niektórzy uważali ją za nieczystą) rodzinę Lisp i rodzinę ML oraz wiele „czysto funkcjonalnych” Haskell, Erlang itp. Nawiasem mówiąc, istnieje wiele języków ogólnych, takich jak Perl, Python Ruby.


26

Funtional Programming

num = 1 
def function_to_add_one(num):
    num += 1
    return num


function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)
function_to_add_one(num)

#Final Output: 2

Programowanie proceduralne

num = 1 
def procedure_to_add_one():
    global num
    num += 1
    return num


procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()
procedure_to_add_one()

#Final Output: 6

function_to_add_one jest funkcją

procedure_to_add_one to procedura

Nawet jeśli uruchomisz tę funkcję pięć razy, za każdym razem zwróci 2

Jeśli wykonasz tę procedurę pięć razy, pod koniec piątego przebiegu otrzymasz 6 .


5
ten przykład jest naprawdę prosty do zrozumienia terminu „bezstanowe” i „niezmienne dane” w programowaniu funkcjonalnym, czytanie wszystkich powyższych definicji i różnic nie rozwiało mojego zamieszania, dopóki nie przeczytałem tej odpowiedzi. Dziękuję Ci!
maximus

13

Aby rozwinąć komentarz Konrada:

W rezultacie czysto funkcjonalny program zawsze daje taką samą wartość dla danych wejściowych, a kolejność oceny nie jest dobrze zdefiniowana;

Z tego powodu kod funkcjonalny jest ogólnie łatwiejszy do zrównoleglenia. Ponieważ (ogólnie) nie ma żadnych skutków ubocznych funkcji i (ogólnie) po prostu działają na podstawie ich argumentów, wiele problemów z współbieżnością znika.

Programowanie funkcjonalne jest również używane, gdy musisz być w stanie udowodnić, że Twój kod jest poprawny. Jest to o wiele trudniejsze w przypadku programowania proceduralnego (niełatwe w funkcjonalnym, ale wciąż łatwiejszym).

Oświadczenie: Nie korzystałem z programowania funkcjonalnego od lat i dopiero niedawno zacząłem się nim ponownie przyglądać, więc może nie mam tutaj całkowitej racji. :)


12

Jedną z rzeczy, których tak naprawdę nie zauważyłem, jest to, że współczesne języki funkcjonalne, takie jak Haskell, bardziej skupiają się na funkcjach pierwszej klasy do kontroli przepływu niż na jawnej rekurencji. Nie trzeba definiować silni rekurencyjnie w Haskell, jak to zostało zrobione powyżej. Myślę, że coś takiego

fac n = foldr (*) 1 [1..n]

jest idealną konstrukcją idiomatyczną i znacznie bliższą duchem użycia pętli niż wyraźnej rekurencji.


10

Programowanie funkcjonalne jest identyczne z programowaniem proceduralnym, w którym nie są używane zmienne globalne .


7

Języki proceduralne mają tendencję do śledzenia stanu (przy użyciu zmiennych) i mają tendencję do wykonywania jako sekwencja kroków. Czysto funkcjonalne języki nie śledzą stanu, używają niezmiennych wartości i mają tendencję do wykonywania jako szereg zależności. W wielu przypadkach status stosu wywołań zawiera informacje równoważne informacjom przechowywanym w zmiennych stanu w kodzie proceduralnym.

Rekurencja to klasyczny przykład programowania funkcjonalnego stylu.


1
Po przeczytaniu tej strony myślałem o tym samym -> „Rekursja to klasyczny przykład programowania w stylu funkcjonalnym”, a ty to wyczyściłeś. Dzięki, teraz myślę, że coś mam.
Mudassir Hussain

6

Konrad powiedział:

W rezultacie czysto funkcjonalny program zawsze daje taką samą wartość dla danych wejściowych, a kolejność oceny nie jest dobrze zdefiniowana; co oznacza, że ​​niepewne wartości, takie jak dane wejściowe użytkownika lub wartości losowe, są trudne do modelowania w czysto funkcjonalnych językach.

Kolejność oceny w czysto funkcjonalnym programie może być trudna (e) do uzasadnienia (szczególnie z lenistwem) lub nawet nieistotna, ale myślę, że powiedzenie, że nie jest dobrze zdefiniowane, sprawia, że ​​brzmi to tak, jakbyś nie wiedział, czy twój program idzie pracować w ogóle!

Być może lepszym wyjaśnieniem byłoby, że przepływ sterowania w programach funkcjonalnych opiera się na tym, kiedy potrzebna jest wartość argumentów funkcji. Dobrą rzeczą jest to, że w dobrze napisanych programach stan staje się jawny: każda funkcja wymienia swoje dane wejściowe jako parametry zamiast arbitralnie mungującego stan globalny. Tak więc na pewnym poziomie łatwiej jest uzasadnić kolejność oceny w odniesieniu do jednej funkcji na raz . Każda funkcja może zignorować resztę wszechświata i skupić się na tym, co musi zrobić. Po połączeniu funkcje mają takie same [1] działanie, jak w oderwaniu.

... niepewne wartości, takie jak dane wprowadzane przez użytkownika lub wartości losowe, są trudne do modelowania w czysto funkcjonalnych językach.

Rozwiązaniem problemu wejściowego w czysto funkcjonalnych programach jest osadzenie imperatywnego języka jako DSL przy użyciu wystarczająco silnej abstrakcji . W imperatywnych (lub nie-czystych funkcjonalnych) językach nie jest to konieczne, ponieważ można „oszukiwać” i przekazywać stan w sposób niejawny, a kolejność oceny jest jawna (czy ci się to podoba, czy nie). Z powodu tego „oszukiwania” i wymuszonej oceny wszystkich parametrów dla każdej funkcji, w imperatywnych językach 1) tracisz możliwość tworzenia własnych mechanizmów kontroli przepływu (bez makr), 2) kod nie jest z natury bezpieczny i / lub równoległy do ​​wątków domyślnie, 3) i wdrożenie czegoś takiego jak cofnięcie (podróż w czasie) wymaga starannej pracy (programista musi przechowywać przepis na odzyskanie starych wartości!), Podczas gdy czyste funkcjonalne programowanie kupuje wszystkie te rzeczy - i jeszcze kilka zapomniałeś - „za darmo”.

Mam nadzieję, że to nie brzmi jak gorliwość, chciałem tylko dodać trochę perspektywy. Programowanie imperatywne, a szczególnie mieszane programowanie paradygmatów w potężnych językach, takich jak C # 3.0, jest nadal całkowicie skutecznym sposobem na załatwienie sprawy i nie ma srebrnej kuli .

[1] ... chyba że w odniesieniu do wykorzystania pamięci (por. Foldl i foldl 'w Haskell).


5

Aby rozwinąć komentarz Konrada:

a kolejność oceny nie jest dobrze określona

Niektóre języki funkcjonalne mają tak zwaną Lazy Evaluation. Co oznacza, że ​​funkcja nie jest wykonywana, dopóki nie jest potrzebna wartość. Do tego czasu sama funkcja jest przekazywana.

Językami proceduralnymi są krok 1 krok 2 krok 3 ... jeśli w kroku 2 powiesz dodać 2 + 2, zrobi to wtedy. W leniwej ocenie powiedziałbyś, że dodaj 2 + 2, ale jeśli wynik nigdy nie zostanie użyty, to nigdy nie doda.


4

Jeśli masz szansę, poleciłbym pobranie kopii Lisp / Scheme i wykonanie w niej kilku projektów. Większość pomysłów, które ostatnio stały się bandwagonami, zostały wyrażone w Lisp dekady temu: programowanie funkcjonalne, kontynuacje (jako zamknięcia), wyrzucanie elementów bezużytecznych, a nawet XML.

Byłby to dobry sposób na uzyskanie przewagi nad wszystkimi obecnymi pomysłami i jeszcze kilkoma innymi, takimi jak obliczenia symboliczne.

Powinieneś wiedzieć, do czego służy funkcjonalne programowanie, a do czego nie. To nie jest dobre na wszystko. Niektóre problemy najlepiej wyrazić w kategoriach skutków ubocznych, w których to samo pytanie daje różne odpowiedzi w zależności od tego, kiedy zostanie zadane.


3

@Creighton:

W Haskell jest funkcja biblioteki o nazwie produkt :

prouduct list = foldr 1 (*) list

lub po prostu:

product = foldr 1 (*)

więc silnia „idiomatyczna”

fac n = foldr 1 (*)  [1..n]

byłoby po prostu

fac n = product [1..n]

To nie daje odpowiedzi na pytanie. Aby skrytykować lub poprosić autora o wyjaśnienia, zostaw komentarz pod postem.
Nick Kitto,

Wierzę, że został opublikowany wiele lat temu, przed dodaniem systemu komentarzy, jeśli możesz w to uwierzyć: stackoverflow.com/help/badges/30/beta?userid=2543
Jared Updike

2

Programowanie proceduralne dzieli sekwencje instrukcji i konstrukcje warunkowe na osobne bloki zwane procedurami, które są sparametryzowane na argumentach będących (niefunkcjonalnymi) wartościami.

Programowanie funkcjonalne jest takie samo, z tym wyjątkiem, że funkcje są pierwszorzędnymi wartościami, więc można je przekazywać jako argumenty do innych funkcji i zwracać jako wynik wywołania funkcji.

Zauważ, że programowanie funkcjonalne jest uogólnieniem programowania proceduralnego w tej interpretacji. Jednak mniejszość interpretuje „programowanie funkcjonalne” jako pozbawione skutków ubocznych, co jest zupełnie inne, ale nie ma znaczenia dla wszystkich głównych języków funkcjonalnych oprócz Haskell.


1

Aby zrozumieć różnicę, należy zrozumieć, że paradygmat „ojca chrzestnego” programowania proceduralnego i funkcjonalnego jest programowaniem imperatywnym .

Zasadniczo programowanie proceduralne jest jedynie sposobem konstruowania programów imperatywnych, w których podstawową metodą abstrakcji jest „procedura”. (lub „funkcja” w niektórych językach programowania). Nawet programowanie zorientowane obiektowo to po prostu inny sposób konstruowania programu imperatywnego, w którym stan jest enkapsulowany w obiekty, stając się obiektem o „aktualnym stanie”, a ponadto ten obiekt ma zestaw funkcji, metod i innych rzeczy, które pozwalają programista manipuluje lub aktualizuje stan.

Teraz, jeśli chodzi o programowanie funkcjonalne, istotą jego podejścia jest to, że określa, jakie wartości należy przyjąć i jak te wartości należy przenieść. (więc nie ma stanu ani danych zmiennych, ponieważ przyjmuje funkcje jako wartości pierwszej klasy i przekazuje je jako parametry do innych funkcji).

PS: zrozumienie każdego paradygmatu programistycznego powinno wyjaśnić różnice między nimi wszystkimi.

PSS: Ostatecznie paradygmaty programowania to po prostu różne podejścia do rozwiązywania problemów.

PSS: ta odpowiedź na quora ma świetne wyjaśnienie.


0

Żadna z odpowiedzi tutaj nie pokazuje idiomatycznego programowania funkcjonalnego. Rekurencyjna czynnikowa odpowiedź jest świetna do reprezentowania rekurencji w FP, ale większość kodu nie jest rekurencyjna, więc nie sądzę, aby ta odpowiedź była w pełni reprezentatywna.

Załóżmy, że masz tablicę ciągów, a każdy ciąg reprezentuje liczbę całkowitą taką jak „5” lub „-200”. Chcesz sprawdzić tę tablicę wejściową ciągów w swoim wewnętrznym przypadku testowym (przy użyciu porównania liczb całkowitych). Oba rozwiązania pokazano poniżej

Proceduralny

arr_equal(a : [Int], b : [Str]) -> Bool {
    if(a.len != b.len) {
        return false;
    }

    bool ret = true;
    for( int i = 0; i < a.len /* Optimized with && ret*/; i++ ) {
        int a_int = a[i];
        int b_int = parseInt(b[i]);
        ret &= a_int == b_int;  
    }
    return ret;
}

Funkcjonalny

eq = i, j => i == j # This is usually a built-in
toInt = i => parseInt(i) # Of course, parseInt === toInt here, but this is for visualization

arr_equal(a : [Int], b : [Str]) -> Bool =
    zip(a, b.map(toInt)) # Combines into [Int, Int]
   .map(eq)
   .reduce(true, (i, j) => i && j) # Start with true, and continuously && it with each value

Podczas gdy czysto funkcjonalne języki są na ogół językami badawczymi (ponieważ świat rzeczywisty lubi bezpłatne efekty uboczne), w prawdziwych językach proceduralnych w stosownych przypadkach stosowana będzie znacznie prostsza składnia funkcjonalna.

Zwykle jest to realizowane za pomocą zewnętrznej biblioteki, takiej jak Lodash , lub dostępnej w nowszych językach, takich jak Rust . Podnoszenia ciężkich programowania funkcjonalnego odbywa się za pomocą funkcji / pojęć takich jak map, filter, reduce, currying, partial, ostatnie trzy z którego można patrzeć na dalsze zrozumienie.

Uzupełnienie

Aby można go było używać w środowisku naturalnym, kompilator zwykle musi opracować sposób wewnętrznej konwersji wersji funkcjonalnej na wersję proceduralną, ponieważ narzut wywołania funkcji jest zbyt wysoki. Przypadki rekurencyjne, takie jak pokazana silnia, wykorzystają sztuczki, takie jak wywołanie ogona, aby usunąć użycie pamięci O (n). Brak efektów ubocznych pozwala funkcjonalnym kompilatorom wdrożyć && retoptymalizację nawet wtedy, gdy .reducejest ona wykonywana jako ostatnia. Korzystanie z Lodash w JS oczywiście nie pozwala na żadną optymalizację, więc jest to hit wydajności (co zwykle nie jest problemem przy tworzeniu stron internetowych). Języki takie jak Rust będą optymalizować wewnętrznie (i mają takie funkcje, jak try_foldpomoc w && retoptymalizacji).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.