Po zapoznaniu się z niektórymi językami programowania funkcjonalnego zawsze zastanawiałem się, dlaczego niektóre języki fp używają jednego lub więcej białych znaków do zastosowania funkcji (i definicji), podczas gdy większość (wszystkie?) Języków imperatywnych / obiektowych używa nawiasów, co wydaje się być bardziej matematycznym sposobem. Myślę też, że ten drugi styl jest znacznie bardziej wyraźny i czytelny niż bez parens.
Jeśli więc mamy funkcję f (x) = x², istnieją dwie możliwości jej wywołania:
FP:
f x
Przykłady:
- ML, Ocaml, F #
- Haskell
- LISP, Schemat (jakoś)
Inne niż FP:
f(x)
Przykłady:
- Prawie wszystkie języki rozkazujące (wiem, zobacz komentarze / odpowiedzi)
- Erlang
- Scala (dopuszcza także „notację operatora” dla pojedynczych argumentów)
Jakie są przyczyny „pomijania” nawiasów?
x²
jako przykładu?Odpowiedzi:
języki funkcjonalne inspirowane są rachunkiem lambda . W tym polu nawiasy nie są używane do zastosowania funkcji.
Czytelność zależy od obserwatora. Nie jesteś przyzwyczajony do czytania. To trochę jak operatory matematyczne. Jeśli rozumiesz skojarzenie, potrzebujesz tylko kilku parens, aby wyjaśnić strukturę swojego wyrażenia. Często ich nie potrzebujesz.
Curry jest również dobrym powodem do zastosowania tej konwencji. W haskell możesz zdefiniować:
W przypadku parens można zastosować dwie konwencje:
f(5, 6)
(nie curry) lubf(5)(6)
(curry). Składnia haskell pomaga przyzwyczaić się do koncepcji curry. Nadal możesz używać wersji bez curry, ale bardziej bolesne jest używanie jej z kombinatoramiZauważ, jak druga wersja zmusza cię do zarejestrowania x jako zmiennej i że podwyrażenie jest funkcją, która bierze liczbę całkowitą i dodaje do niej 5? Wersja curry jest znacznie lżejsza, ale przez wielu uważana za bardziej czytelną.
Programy Haskell w szerokim zakresie wykorzystują częściową aplikację i kombinatory do definiowania i komponowania abstrakcji, więc nie jest to zabawkowy przykład. Dobry interfejs funkcyjny to taki, w którym kolejność parametrów zapewnia przyjazne korzystanie z curry.
Kolejna kwestia: należy wywołać funkcję bez parametrów
f()
. W Haskell, ponieważ manipulujesz tylko niezmiennymi leniwymi wartościami, po prostu piszeszf
i traktujesz to jako wartość, która będzie musiała wykonać pewne obliczenia, gdy zajdzie taka potrzeba. Ponieważ jego ocena nie spowoduje żadnych skutków ubocznych, nie ma sensu mieć innej notacji dla funkcji bez parametrów i jej zwracanej wartości.Istnieją również inne konwencje dotyczące zastosowania funkcji:
źródło
f(a, ,b)
lubadd(a, )
czyadd(, b)
wydaje się bardziej elastyczne domyślnie.Podstawową ideą jest uczynienie najważniejszej operacji (aplikacji funkcyjnej) najłatwiejszą do odczytania i najłatwiejszą do napisania. Spacja jest bardzo mało czytelna i bardzo łatwa do pisania.
Pamiętaj, że nie jest to specyficzne dla języków funkcjonalnych, np. W Smalltalk , jednym z pierwszych języków OO i językach przez niego inspirowanych ( Self , Newspeak , Objective-C), ale także w Io i językach przez niego inspirowanych (Ioke, Seph), biały znak służy do wywołań metod.
W stylu smalltalk:
(W tym drugim przypadku nazwa metody to
replace:with:
.)Styl Io:
Scala dopuszcza również spacje dla wywołań metod:
I pomijając nawiasy, jeśli jest tylko jeden argument:
Ruby pozwala również pominąć nawiasy:
Nie całkiem:
Notacja matematyczna ewoluowała przez długi czas w okropnie niespójny sposób.
Jeśli w ogóle, języki funkcjonalne czerpią inspirację z rachunku λ, w którym aplikacja funkcji jest pisana za pomocą białych znaków.
źródło
Nawias dla funkcji jest tylko jednym z wielu siodeł, które nam zostawił Euler. Jak wszystko inne matematyka wymaga konwencji, gdy istnieje kilka sposobów na zrobienie czegoś. Jeśli twoje wykształcenie matematyczne obejmuje jedynie przedmiot niematerialny na uniwersytecie, prawdopodobnie nie znasz zbyt wielu dziedzin, w których zastosowanie funkcji odbywa się szczęśliwie bez żadnej z tych nonsensownych nawiasów (np. Geometria różniczkowa, algebra abstrakcyjna). I nawet nie wspominasz o funkcjach, które są stosowane jako poprawki (prawie we wszystkich językach), „outfix”, jak przyjmowanie norm, lub schematycznie (Befunge, Topologia algebraiczna).
W odpowiedzi powiedziałbym, że wynika to ze znacznie większego odsetka programistów funkcjonalnych i projektantów językowych posiadających bogate wykształcenie matematyczne. Von Neumann mówi: „Młody człowieku, w matematyce nie rozumiesz rzeczy. Po prostu się do nich przyzwyczajasz.”, Z pewnością dotyczy to notacji.
źródło
f(x)
vs.sin x
vs.x²
vs.|x|
vs.x!
vs.x + y
vs.xy
vs.½
vs. suma vs. całka vs.…Chociaż w odpowiedzi Simona jest wiele prawdy, myślę, że istnieje również bardziej praktyczny powód. Natura programowania funkcjonalnego zwykle generuje znacznie więcej nawiasów niż programowanie imperatywne, ze względu na tworzenie łańcuchów funkcji i skład. Te wzorce tworzenia łańcuchów i kompozycji zazwyczaj są w stanie być jednoznacznie przedstawione bez nawiasów.
Najważniejsze jest to, że wszystkie te nawiasy są denerwujące do czytania i śledzenia. Jest to prawdopodobnie najważniejszy powód, dla którego LISP nie jest bardziej popularny. Więc jeśli uda ci się uzyskać moc programowania funkcjonalnego bez uciążliwości związanych z nadmiarem nawiasów, myślę, że projektanci języków będą dążyli w tym kierunku. W końcu projektanci języków są również użytkownikami języków.
Nawet Scala pozwala programiście pomijać nawiasy w pewnych okolicznościach, które zdarzają się dość często przy programowaniu w funkcjonalnym stylu, dzięki czemu uzyskuje się to, co najlepsze z obu światów. Na przykład:
Pareny na końcu są niezbędne do skojarzenia, a pozostałe są pomijane (podobnie jak kropki). Pisanie w ten sposób podkreśla połączony charakter wykonywanych operacji. Być może nie jest to konieczne dla programisty, ale dla programisty funkcjonalnego pisanie w ten sposób jest bardzo naturalne i płynne, bez konieczności zatrzymywania się i wstawiania składni, która nie dodaje żadnego znaczenia programowi, ale jest tylko po to, aby uszczęśliwić kompilator .
źródło
Oba przesłanki są błędne.
Te języki funkcjonalne nie zajmują miejsca na aplikacje funkcyjne. To, co robią, to po prostu analizuje każde wyrażenie występujące po funkcji jako argument.
Oczywiście jeśli używasz ani przestrzeń, ani parens to zazwyczaj nie działa, po prostu dlatego, że ekspresja nie jest prawidłowo tokenised
Ale jeśli te języki byłyby ograniczone do 1-znakowych nazw zmiennych, to też by działały.
Konwencje matematyczne zwykle nie wymagają nawiasów do zastosowania funkcji. Matematycy często nie tylko piszą sin x - w przypadku funkcji liniowych (zwykle wtedy nazywanych operatorami liniowymi) bardzo często zapisuje się argument bez parens, być może dlatego, że (podobnie jak każda funkcja w programowaniu funkcjonalnym) funkcje liniowe są często obsługiwane bez bezpośredniego dostarczania argument.
Tak naprawdę twoje pytanie sprowadza się do: dlaczego niektóre języki wymagają nawiasów do zastosowania funkcji? Najwyraźniej niektórzy ludzie, tacy jak ty, uważają to za bardziej czytelne. Zdecydowanie się z tym nie zgadzam: jedna para parenów jest miła, ale gdy tylko dwie z nich zostaną zagnieżdżone, zaczyna się mylić. Kod Lisp pokazuje to najlepiej i prawie wszystkie języki funkcjonalne wyglądałyby podobnie zagracone, gdybyś potrzebował wszędzie parens. Nie zdarza się to tak często w imperatywnych językach, ale głównie dlatego, że języki te nie są wystarczająco wyraziste, aby napisać zwięzłe, jasne jednostronne linie.
źródło
object method: args
, Cel C ma[object method: args]
, a Ruby i Perl pozwalają na pomijanie nawiasów w wywołaniach funkcji i metod, wymagając tylko od nich rozwiązania niejednoznaczności.Małe wyjaśnienie historyczne: pierwotna notacja w matematyce nie zawierała nawiasów !
Notację fx dla dowolnej funkcji x wprowadził Johan Bernoulli około 1700 roku krótko po tym, jak Leibniz zaczął mówić o funkcjach (faktycznie Bernoulli napisał x ). Ale wcześniej wiele osób używało już notacji takich jak sin x lub lx (logarytm x ) dla określonych funkcji x , bez nawiasów. Podejrzewam, że właśnie dlatego wielu ludzi wciąż pisze sin x zamiast sin (x) .
Euler, który był uczniem Bernoulliego, przyjęty Bernoulliego φ x i zmienił się w greckiej litery alfabetu łacińskiego, pisanie fx . Później zauważył, że łatwo pomylić f z „ilością” i wierzyć, że fx był produktem, więc zaczął pisać f: x . Stąd notacja f (x) nie wynika z Eulera. Oczywiście Euler potrzebował nawiasów z tego samego powodu, dla którego nadal potrzebujemy nawiasów w funkcjonalnych językach programowania: aby odróżnić na przykład (fx) + y od f (x + y) . Podejrzewam, że ludzie po Eulerze przyjęli nawias jako domyślny, ponieważ widzieli głównie Eulera piszącego wyrażenia złożone, takie jak f (ax + b). Rzadko pisał tylko fx .
Dowiedz się więcej na ten temat: Czy Euler kiedykolwiek pisał f (x) w nawiasie? .
Nie wiem, czy projektanci funkcjonalnych języków programowania czy wynalazcy rachunku lambda znali historyczne korzenie ich zapisu. Osobiście uważam, że notacja bez nawiasów jest bardziej naturalna.
źródło