Czy Ruby jest językiem funkcjonalnym?

88

Wikipedia podaje, że Ruby jest językiem funkcjonalnym, ale nie jestem do tego przekonany. Dlaczego lub dlaczego nie?

Esteban Araya
źródło
4
Prawdopodobnie dlatego, że Twoje pytanie jest bardzo krótkie, chociaż osobiście nie mam z nim żadnego problemu!
ljs
Są już dobre odpowiedzi, więc żeby je uzupełnić, parę treści omawiających FP i Ruby: code.google.com/p/tokland/wiki/RubyFunctionalProgramming slideshare.net/tokland/functional-programming-with-ruby-9975242
tokland
1
Jeśli ktoś jest zainteresowany tym tematem, obejrzyj to, a dowiesz się, jak Ruby można wykorzystać w funkcjonalny sposób, jakie są korzenie programowania funkcjonalnego, dlaczego Ruby nie jest językiem funkcjonalnym, nawet jeśli jest w stanie programować funkcjonalnie: youtube .com / watch? v = 5ZjwEPupybw
maddin2code

Odpowiedzi:

29

Zdecydowanie uważam, że w Rubim możesz użyć stylu funkcjonalnego.

Jednym z najbardziej krytycznych aspektów możliwości programowania w stylu funkcjonalnym jest to, czy język obsługuje funkcje wyższego rzędu ... co robi Ruby.

To powiedziawszy, łatwo jest programować w Rubim również w niefunkcjonalnym stylu. Innym kluczowym aspektem stylu funkcjonalnego jest brak stanu i rzeczywiste funkcje matematyczne, które zawsze zwracają tę samą wartość dla danego zestawu danych wejściowych. Można to zrobić w Rubim, ale nie jest to wymuszone w języku, jak coś bardziej funkcjonalnego, jak Haskell.

Więc tak, obsługuje styl funkcjonalny, ale pozwala również programować w stylu niefunkcjonalnym.

Mike Stone
źródło
4
Używając tych kryteriów, możesz powiedzieć, że Smalltalk działa, ponieważ ma bloki?
OscarRyz
Dobra odpowiedź, ale jedna dziura w grze - funkcje wyższego rzędu nie są ściśle wymagane dla stylu funkcjonalnego. np. Możesz osiągnąć styl funkcjonalny w Javie (który nie ma funkcji pierwszej klasy / wyższego rzędu), definiując obiekty funkcji i komponując je tak, aby uzyskać taki sam efekt jak funkcja wyższego rzędu.
mikera
2
Po prostu chcę powiedzieć, że @peter zapytał, Is ruby a functional language?a prosta odpowiedź brzmi: nie. Ruby to język zorientowany obiektowo z pewnymi funkcjami.
Elias Perez,
58

Nie ma znaczenia, czy język jest językiem funkcjonalnym, czy też nie. Programowanie funkcyjne to teza, którą najlepiej wyjaśnili Philip Wadler (The Essence of Functional Programming) i John Hughes (Why Functional Programming Matters).

Znaczące pytanie brzmi: „Jak podatny jest Ruby na osiągnięcie tezy o programowaniu funkcyjnym?” Odpowiedź brzmi „bardzo słabo”.

Niedawno wygłosiłem wykład na ten temat. Oto slajdy.

Tony Morris
źródło
3
Slajdy, które dałeś, nie wspominały, dlaczego Ruby jest „bardzo słabo podatny na osiągnięcie tezy FP”. Dlaczego C # jest bardziej przystępny niż Java (OK, łatwiejsze funkcje anonimowe?)? Czy to dlatego, że w Rubim można mieć zmienne globalne?
kizzx2
7
Nie, slajdy nie zawierają tego szczegółu, ponieważ jest to dość obszerny temat. Na przykład, ryzykując nadmiernym uproszczeniem, Ruby wymusza model oceny (call-by-value), który zapewnia brak kompozycji programów. Konsekwencje tego można łatwo nie docenić. Ruby jest również powiązany z ideą, że program jest sekwencją efektów. Oznacza to, że Ruby robi wszystko, co w jego mocy, aby utrudnić / uniemożliwić użycie innego modelu obliczeniowego. Mam nadzieję, że ten krótki komentarz pomoże.
Tony Morris,
2
+1 za wskazanie niejednoznaczności w klasyfikowaniu języków jako funkcjonalnych. Do diabła, napisałem funkcjonalne C!
Eli
1
Dlaczego C # jest bardziej podatny niż Ruby?
dan_l
1
Skuteczna odpowiedź tylko na link, ponieważ przenosi krytyczną część wyjaśnienia (w rzeczywistości całe wyjaśnienie) do zewnętrznego łącza. Teraz, gdy łącze zniknęło, odpowiedź stała się bezużyteczna.
ivan_pozdeev
34

Ruby obsługuje funkcje wyższego poziomu (zobacz Array # map, inject, & select), ale nadal jest to konieczny język obiektowy.

Jedną z kluczowych cech języka funkcjonalnego jest to, że unika on stanu zmiennego. Języki funkcjonalne nie mają pojęcia zmiennej, tak jak w Ruby, C, Javie lub jakimkolwiek innym języku imperatywnym.

Inną kluczową cechą języka funkcjonalnego jest to, że koncentruje się on na definiowaniu programu w kategoriach „co”, a nie „jak”. Podczas programowania w języku obiektowym piszemy klasy i metody, aby ukryć implementację („jak”) przed „co” (nazwa klasy / metody), ale ostatecznie metody te są nadal zapisywane przy użyciu sekwencji instrukcji. W języku funkcjonalnym nie określa się kolejności wykonywania, nawet na najniższym poziomie.

Mikrofon
źródło
3
Zgadzam się z większością twojego stwierdzenia, jednak nie zgadzam się z stwierdzeniem „Języki funkcjonalne nie mają pojęcia zmiennych, tak jak w Javie itp.” W haskell możesz używać zmiennych w czystych funkcjach, możesz nawet przypisać funkcję do zmiennej, największa różnica polega na tym, że po przypisaniu zmiennej nie można jej później modyfikować.
HHC
6
HHC z definicji zmienna to wartość, która może się zmieniać . Mówisz o wartościach.
Scala Newb
W istocie „niemodyfikowalne zmienne” Haskella to po prostu funkcje stałe bez parametrów (definicji).
raindev
16

Uważam, że wspieranie, czyli umiejętność programowania w języku w stylu funkcjonalnym , nie czyni języka funkcjonalnego.

Mogę nawet napisać kod w Javie w funkcjonalnym stylu, jeśli chcę skrzywdzić moich kolegów i siebie za kilka miesięcy .

Posiadanie języka funkcjonalnego nie chodzi tylko o to, co można zrobić, takich jak funkcje wyższego rzędu, funkcji pierwszej klasy i zmiękczania. Dotyczy również tego, czego nie można zrobić, na przykład skutków ubocznych w czystych funkcjach.

Jest to ważne, ponieważ w dużej mierze jest to powód, dla którego programy funkcjonalne lub kod funkcjonalny w ogóle jest łatwiejszy do rozważenia. A kiedy łatwiej jest zrozumieć kod, błędy stają się płytsze i przenoszą się na powierzchnię koncepcyjną, gdzie można je naprawić, co z kolei daje mniej błędnego kodu.

Ruby jest w swej istocie zorientowany obiektowo, więc nawet jeśli ma dość dobre wsparcie dla stylu funkcjonalnego, sam nie jest językiem funkcjonalnym.

W każdym razie to moja nienaukowa opinia.

Edytować: Z perspektywy czasu i biorąc pod uwagę dobre komentarze, jakie otrzymałem do tej odpowiedzi do tej pory, myślę, że porównanie zorientowane obiektowo i funkcjonalnie dotyczy jabłek i pomarańczy.

Prawdziwym wyróżnikiem jest to, że w wykonaniu jest imparatywny lub nie. Języki funkcyjne mają wyrażenie jako podstawowy konstrukt językowy, a kolejność wykonywania jest często niezdefiniowana lub definiowana jako leniwa. Ścisłe wykonanie jest możliwe, ale używane tylko w razie potrzeby. W języku imparatywnym, ścisłe wykonanie jest ustawieniem domyślnym i chociaż leniwe wykonanie jest możliwe, jest to często niezdarne i może mieć nieprzewidywalne rezultaty w wielu skrajnych przypadkach.

Teraz, to jest moja opinia nienaukowe.

Chris Vest
źródło
Myślę, że możesz zrobić o wiele lepsze argumenty za nazywaniem Rubiego funkcjonalnym niż Java ... nie, Ruby nie jest ściśle funkcjonalny, ale dość łatwo jest użyć w nim funkcjonalnego stylu ... łatwo zmienić go z powrotem na niedziałający
Mike Stone
1
Tak, Mike, jeśli chcesz kodować w funkcjonalnym stylu, Ruby jest ogromnym ulepszeniem w stosunku do Javy. Używałem Javy tylko po to, aby wyolbrzymić i wskazać na sedno sprawy.
Chris Vest
Więc skoro D ma czyste funkcje, nazwałbyś D językiem funkcjonalnym? digitalmars.com/d/2.0/function.html#pure-functions
Peter Burns
3
Wiele osób uważa języki funkcjonalne Lisp i Scheme, głównie z powodu powszechnego stosowania funkcji anonimowych. A jednak brakuje im gwarantowanych czystych funkcji. Ograniczenie tego terminu do języków obsługujących czyste funkcje wydaje się zbyt restrykcyjne.
skymt
13

Ruby będzie musiał spełnić następujące wymagania, aby był "PRAWDZIWIE" funkcjonalny.

Niezmienne wartości: po ustawieniu „zmiennej” nie można jej zmienić. W Rubim oznacza to, że musisz skutecznie traktować zmienne jak stałe. Ten język nie jest w pełni obsługiwany, będziesz musiał ręcznie zablokować każdą zmienną.

Brak efektów ubocznych: po przekazaniu danej wartości funkcja musi zawsze zwracać ten sam wynik. To idzie w parze z posiadaniem niezmiennych wartości; funkcja nigdy nie może przyjąć wartości i zmienić jej, ponieważ spowodowałoby to efekt uboczny, który jest styczny do zwracania wyniku.

Funkcje wyższego rzędu: są to funkcje, które dopuszczają funkcje jako argumenty lub używają funkcji jako wartości zwracanej. Jest to prawdopodobnie jedna z najbardziej krytycznych cech każdego języka funkcjonalnego.

Currying: włączone przez funkcje wyższego rzędu, currying przekształca funkcję, która przyjmuje wiele argumentów, w funkcję, która przyjmuje jeden argument. Idzie to w parze z częściową aplikacją funkcji, która przekształca funkcję wieloargumentową w funkcję, która przyjmuje mniej argumentów niż pierwotnie.

Rekursja: zapętlenie przez wywołanie funkcji z jej wnętrza. Gdy nie masz dostępu do danych, które można modyfikować, rekurencja jest używana do tworzenia i łączenia konstrukcji danych. Dzieje się tak, ponieważ pętla nie jest koncepcją funkcjonalną, ponieważ wymaga przekazywania zmiennych w celu przechowywania stanu pętli w danym momencie.

Leniwa ocena lub opóźniona ocena: opóźnianie przetwarzania wartości do momentu, gdy jest to rzeczywiście potrzebne. Jeśli, na przykład, masz kod, który wygenerował listę liczb Fibonacciego z włączoną funkcją leniwego obliczania, nie zostanie to faktycznie przetworzone i obliczone, dopóki jedna z wartości w wyniku nie będzie wymagana przez inną funkcję, taką jak puts.

Propozycja (tylko myśl) Byłoby wspaniale mieć jakąś definicję, aby mieć plikmode dyrektywę do deklarowania plików z paradygmatem funkcjonalnym, przykład

tryb „funkcjonalny”

Elias Perez
źródło
2
Zapraszamy. Zapraszam do lektury o językach funkcjonalnych. Lisp jest dziadkiem wszystkich funkcjonalnych języków, ML (CAML) i Erlang / Elixir. To naprawdę zmienia twoją perspektywę rzeczy. Nie jestem daleko od eksperta, ale stały student informatyki lubi czytać i uczyć się nowych rzeczy.
Elias Perez,
Dobrze zorganizowana odpowiedź. Bardzo chciałbym zbadać, jak dobrze Ruby obsługuje te rzeczy. Uważam, że funkcje wyższego rzędu, currying i rekurencja są obsługiwane / możliwe w Ruby. Proszę mnie poprawić, jeśli się mylę.
Michael Dorst
9

Ruby to język wieloparadygmatyczny, który obsługuje funkcjonalny styl programowania.

skymt
źródło
8
dostarczyć dowody
Mirzhan Irkegulov
4

Ruby jest językiem zorientowanym obiektowo, który może obsługiwać inne paradygmaty (funkcjonalne, imperatywne itp.). Jednak ponieważ wszystko w Rubim jest obiektem, jest to przede wszystkim język OO.

przykład:

"hello" .reverse () = "olleh", każdy łańcuch jest instancją obiektu typu string i tak dalej, i tak dalej.

Zaznajomić się tutaj lub tutaj

kamflan
źródło
Nigdy tak naprawdę nie rozumiałem, jak „wszystko jest obiektem” sprawia, że ​​Ruby jest bardziej OO. Zgadzam się, że Ruby jest przede wszystkim OO, ale „wszystko jest obiektem” tak naprawdę oznacza tylko, że nie ma typów „prymitywnych”, co ma bardzo mały wpływ na zdolność programisty do pisania programów w stylu OO, biorąc pod uwagę, że istnienie prymitywnych Typy ogólnie po prostu oznaczają, że istnieją cztery lub pięć typów, które nie mają żadnych metod.
Michael Dorst
4

To zależy od twojej definicji „języka funkcjonalnego”. Osobiście uważam, że sam termin jest dość problematyczny, gdy jest używany jako absolut. Bycie „językiem funkcjonalnym” ma więcej aspektów niż zwykłe funkcje językowe, a większość zależy od tego, skąd patrzysz. Na przykład kultura otaczająca język jest pod tym względem dość ważna. Czy zachęca do funkcjonalnego stylu? A co z dostępnymi bibliotekami? Czy zachęcają do korzystania z nich w sposób funkcjonalny?

Większość ludzi nazwałaby na przykład Scheme językiem funkcjonalnym. Ale co z Common Lispem? Oprócz problemu z wielokrotną / pojedynczą przestrzenią nazw i gwarantowaną eliminacją wywołań końcowych (które również obsługują niektóre implementacje CL, w zależności od ustawień kompilatora), niewiele jest rzeczy, które sprawiają, że Scheme jako język lepiej nadaje się do programowania funkcjonalnego niż Common Lisp, i mimo to, większość Lisperów nie nazwałaby CL językiem funkcjonalnym. Czemu? Ponieważ otaczająca go kultura w dużym stopniu zależy od nadrzędnych cech CL (takich jak na przykład makro LOOP, na które większość Schemerów prawdopodobnie by się nie przejrzała).

Z drugiej strony programista C może uznać CL za język funkcjonalny. W końcu większość kodu napisanego w jakimkolwiek dialekcie Lisp jest z pewnością znacznie bardziej funkcjonalna niż zwykły blok kodu C. Podobnie Schemat jest bardzo imperatywnym językiem w porównaniu z Haskellem. Dlatego nie sądzę, aby kiedykolwiek istniała jednoznaczna odpowiedź tak / nie. To, czy nazwać język funkcjonalnym, czy nie, w dużej mierze zależy od twojego punktu widzenia.

Matthias Benkard
źródło
W jakim sensie Haskell nie jest językiem czysto funkcjonalnym? A może Miranda (mniej znany funkcjonalny język programowania)? kursy.cs.washington.edu/courses/cse505/99au/functional/… "Haskell to standardowy, czysty język funkcjonalny"
barlop
2

Wydaje mi się, że Ruby również nie jest językiem wieloparadygmatycznym. Wielu paradygmat jest zwykle używany przez ludzi, którzy chcą nazwać swój ulubiony język czymś, co jest przydatne w wielu różnych dziedzinach.

Opisałbym Ruby to obiektowy język skryptowy. Tak, funkcje są obiektami pierwszej klasy (w pewnym sensie), ale to nie czyni z tego języka funkcjonalnego. IMO, dodam.

JesperE
źródło
4
Typ języka jest definiowany przez obsługiwane style programowania; o tym z kolei decydują jego funkcje. Funkcje pierwszej klasy i anonimowe = minimalne programowanie funkcjonalne. Ruby obsługuje programowanie obiektowe, ale go nie wymaga: nigdy nie musisz definiować klasy. Stąd wieloparadygmat.
skymt
2

Rekursja jest powszechna w programowaniu funkcjonalnym. Prawie każdy język obsługuje rekursję, ale algorytmy rekurencyjne są często nieskuteczne, jeśli nie ma wywołania ogonowego optymalizacji (TCO).

Funkcjonalne języki programowania są zdolne do optymalizacji rekurencji ogona i mogą wykonywać taki kod w stałej przestrzeni. Niektóre implementacje Rubiego optymalizują rekurencję ogonową, inne nie, ale generalnie implementacje Rubiego nie są wymagane do osiągnięcia całkowitego kosztu posiadania. Zobacz Czy Ruby przeprowadza optymalizację wywołań ogonowych?

Tak więc, jeśli napiszesz jakiś funkcjonalny styl Rubiego i polegasz na całkowitym koszcie posiadania jakiejś konkretnej implementacji, twój kod może być bardzo nieefektywny w innym interpreterze Rubiego. Myślę, że właśnie dlatego Ruby nie jest językiem funkcjonalnym (podobnie jak Python).

śastanin
źródło
Całkowity koszt posiadania jest interesujący, ponieważ zasadniczo zmienia zachowanie programu. W niektórych przypadkach nie jest to widoczne dla programu, ale w innych jest to np. Ślady wstecznego wyjątku. Dlatego nie zawsze jest to odpowiednia optymalizacja.
ioquatix
2

Ściśle mówiąc, nie ma sensu opisywać języka jako „funkcjonalnego”; większość języków umożliwia programowanie funkcjonalne. Nawet C ++ jest.

Styl funkcjonalny jest mniej więcej podzbiorem imperatywnych funkcji języka, wspieranych przez cukier składniowy i niektóre optymalizacje kompilatora, takie jak niezmienność i spłaszczanie rekurencji ogona,

Ta ostatnia jest prawdopodobnie niewielką techniczną cechą specyficzną dla implementacji i nie ma nic wspólnego z rzeczywistym językiem. Kompilator x64 C # 4.0 optymalizuje rekurencję ogonową, podczas gdy kompilator x86 nie robi tego z jakiegoś głupiego powodu.

Cukier syntaktyczny można zwykle obejść do pewnego stopnia lub innego, zwłaszcza jeśli język ma programowalny prekompilator (np. C's #define).

Nieco bardziej sensowne może być pytanie „czy język __ obsługuje programowanie imperatywne?”, A odpowiedź, na przykład w przypadku Lispa, brzmi „nie”.

Rei Miyasaka
źródło
1

Proszę spojrzeć na początek książki: „A-Great-Ruby-eBook” . Omawia bardzo konkretny temat, o który pytasz. W Rubim możesz wykonywać różne rodzaje programowania. Jeśli chcesz programować jak funkcjonalnie, możesz to zrobić. Jeśli chcesz programować tak, jak trzeba, możesz to zrobić. Jest to pytanie definiujące, jak funkcjonalny jest ostatecznie Ruby. Zobacz odpowiedź użytkownika camflan.

Léo Léopold Hertz 준영
źródło