Czy wszystkie języki są w zasadzie takie same?

39

Ostatnio musiałem zrozumieć projekt małego programu napisanego w języku, o którym nie miałem pojęcia ( ABAP , jeśli musisz wiedzieć). Mogłem to rozgryźć bez większych trudności.

Zdaję sobie sprawę, że opanowanie nowego języka to zupełnie inna gra w piłkę, ale samo zrozumienie zamiaru kodu (w szczególności standardowego kodu produkcyjnego, który niekoniecznie jest skomplikowany) w dowolnym języku jest proste, jeśli znasz już kilka języków (najlepiej jeden procesowy / OO i jeden funkcjonalny).

Czy to na ogół prawda? Czy wszystkie języki programowania składają się z podobnych konstrukcji, takich jak pętle, instrukcje warunkowe i przekazywanie komunikatów między funkcjami? Czy istnieją języki inne niż ezoteryczne, których typowy programista Java / Ruby / Haskell nie byłby w stanie zrozumieć? Czy wszystkie języki mają wspólne pochodzenie?

Anirudh
źródło
4
Poprowadzę cię do Beating the Averages Paula Grahama. Możesz, ale nie chcesz, przeczytać całość, ale dla odpowiedniej części poszukaj nagłówka „Paradoks Blub”. Grahamowi nie przeszkadza umieszczanie kotwic w jego ścianie tekstu, więc nie mogę bezpośrednio z nim linkować.
kwatford
4
Języki nie mają wspólnego pochodzenia. Ale wszystkie języki próbują rozwiązać jakiś problem. Myślę, że jest to nieco analogiczne do języka mówionego. Celem jest wyrażenie siebie. Nie mogę powiedzieć, że zrozumienie języków na podstawie znajomości 1 procedury / OO / funkcjonalności jest proste. Nie zrobiłem tego, ale gdybym zadał to pytanie, spojrzałbym na perl lub seplenienie z mnóstwem nawiasów i nie byłbym w stanie powiedzieć, że znajomość 1 języka każdego typu jest wystarczająca.
shahkalpesh
1
W takim przypadku: rachunek Lambda. Być może nie jest to „prawdziwy” język, ale w pewnym sensie jest matką wszystkich języków programowania. Kiedyś musiałem zaimplementować funkcjonalny język, który skompilował się w wyrażenia lambda (które następnie zostały bezpośrednio zinterpretowane). Wyniki były (przynajmniej dla mnie) nieczytelne pomimo zachowania wszystkich odpowiednich identyfikatorów. Szczególnie funkcje rekurencyjne za pomocą kombinatora Y. Jedynym praktycznym sposobem, aby dowiedzieć się, co zrobiły niektóre przykładowe wyrażenia, była ich ręczna ocena. Proste rzeczy, takie jak fibonnaci i sortowanie po scaleniu, były nieczytelne.
kwatford
2
Jeśli znasz języki funkcjonalne, powinieneś wiedzieć, że pętle nie są możliwe w każdym języku.
jalf
Piet jest zupełnie inny. :)

Odpowiedzi:

88

Podstawy większości języków proceduralnych są prawie takie same.

Oni oferują:

  • Skalarne typy danych: zwykle wartości logiczne, liczby całkowite, zmiennoprzecinkowe i znaki
  • Złożone typy danych: tablice (ciągi znaków są specjalnymi przypadkami) i struktury
  • Podstawowe konstrukcje kodu: arytmetyka na skalarach, dostęp do tablicy / struktury, przypisania
  • Proste struktury kontrolne: if-then, if-then-else, while, dla pętli
  • Pakiety bloków kodu: funkcje, procedury z parametrami
  • Zakresy: obszary, w których identyfikatory mają określone znaczenie

Jeśli to zrozumiesz, dobrze znasz 90% języków na naszej planecie. To, co sprawia, że ​​te języki są nieco trudniejsze do zrozumienia, to niesamowita różnorodność dziwnej składni, której ludzie używają, by mówić te same podstawowe rzeczy. Niektórzy używają notacji zwięzłej z nieparzystą interpunkcją (APL to ekstremum). Niektóre używają wielu słów kluczowych (COBOL jest doskonałym przedstawicielem). To nie ma większego znaczenia. Liczy się to, że język jest wystarczająco kompletny, aby wykonywać złożone zadania bez powodowania odrywania włosów. (Spróbuj zakodować poważne hakowanie ciągów w skrypcie powłoki systemu Windows DOS: jest on zdolny do Turinga, ale jest naprawdę zły we wszystkim).

Bardziej interesująca oferta języków proceduralnych

  • Zagnieżdżone lub leksykalne zakresy, przestrzenie nazw
  • Wskaźniki pozwalające jednej jednostce odnosić się do drugiej z dynamicznym przydzielaniem pamięci
  • Pakowanie powiązanego kodu: paczki, obiekty z metodami, cechy
  • Bardziej zaawansowana kontrola: rekurencja, kontynuacje, zamykanie
  • Wyspecjalizowane operatory: operacje na łańcuchach i tablicach, funkcje matematyczne

Choć technicznie nie jest to właściwość języka, ale właściwość ekosystemu, w którym żyją takie języki, są to biblioteki, które są łatwo dostępne lub wyposażone w język jako część narzędzia programistycznego. Posiadanie szerokiej gamy udogodnień bibliotecznych upraszcza / przyspiesza pisanie aplikacji po prostu dlatego, że nie trzeba wymyślać na nowo tego, co robią biblioteki. Podczas gdy Java i C # są powszechnie uważane za dobre języki same w sobie, tym, co czyni je naprawdę przydatnymi, są ogromne biblioteki, które się z nimi wiążą, i łatwo dostępne biblioteki rozszerzeń.

Trudniej zrozumieć języki, które nie są proceduralne:

  • Języki czysto funkcjonalne, bez zadań i skutków ubocznych
  • Języki logiczne, takie jak Prolog, w których występują obliczenia symboliczne i unifikacja
  • Języki dopasowywania wzorów, w których określasz kształty dopasowane do problemu, a często akcje są wyzwalane przez dopasowanie
  • Języki ograniczeń, które pozwalają określać relacje i automatycznie rozwiązywać równania
  • Języki opisu sprzętu, w których wszystko działa równolegle
  • Języki specyficzne dla domeny, takie jak SQL, kolorowe sieci Petriego itp.

Istnieją dwa główne style reprezentacji języków:

  • Oparty na tekście, w którym identyfikatory nazywają encje i przepływy informacji są niejawnie kodowane w formułach, które używają identyfikatorów do nazwania encji (Java, APL, ...)
  • Graficzny, w którym elementy są rysowane jako węzły, a relacje między elementami są rysowane jako wyraźne łuki między tymi węzłami (UML, Simulink, LabView)

Języki graficzne często dopuszczają podsieci tekstowe jako adnotacje w węzłach i na łukach. Języki graficzne Odera rekurencyjnie dopuszczają wykresy (z tekstem :) w węzłach i na łukach. Naprawdę dziwne języki graficzne pozwalają, aby wykresy adnotacyjne wskazywały na adnotowane wykresy.

Większość tych języków opiera się na bardzo małej liczbie modeli obliczeniowych:

  • Rachunek lambda (podstawa dla Lisp i wszystkich języków funkcjonalnych)
  • Systemy pocztowe (lub techniki przepisywania ciągów / drzewek / wykresów)
  • Maszyny Turinga (modyfikacja stanu i wybór nowych komórek pamięci)

Biorąc pod uwagę fakt, że większość branży koncentruje się na językach proceduralnych i złożonych strukturach kontrolnych, możesz dobrze skorzystać, jeśli nauczysz się jednego z bardziej interesujących języków w tej kategorii, zwłaszcza jeśli zawiera on pewien rodzaj orientacji obiektowej.

Bardzo polecam naukę Schematu, w szczególności z naprawdę wspaniałej książki: Struktura i interpretacja programów komputerowych . Opisuje wszystkie te podstawowe pojęcia. Jeśli znasz te rzeczy, inne języki będą wydawać się proste, z wyjątkiem głupiej składni.

Ira Baxter
źródło
3
Świetna odpowiedź! Jako kontynuację (czy istnieje sposób zadawania dalszych pytań w SO?), Czy jest jeden język, który mogę opanować i twierdzić, że rozumiem wszystkie pojęcia w oprogramowaniu do programowania? Czy byłby to Lisp (lub dialekt taki jak Scheme)?
@Anirudh: Nie ma formalnego mechanizmu monitorowania, ale możesz otworzyć nowe pytanie. Jeśli zawiera uzasadnienie i link do tego pytania, może nawet nie zostać zamknięte. ;) Aby odpowiedzieć na twoje dalsze działania, całym sercem wierzę, że nie ma tylko jednego języka, ponieważ paradygmaty są zbyt różne.
@Anirudh: Uzgodniony z Johnem Y, nie ma tylko jednego. Ale jeśli jesteś stosunkowo nowy w tej dziedzinie, powinieneś poświęcić sporo energii na opanowanie paradygmatu proceduralnego (uważam OO za specjalizację). Nie zaszkodzi spojrzeć na inne paradygmaty (logika, ograniczenia, przepływ danych), aby zorientować się, jak działają, ale w większości codziennych prac przemysłowych języki proceduralne są w zasadzie królem.
Ira Baxter
1
Podobnie jak w przypadku języków naturalnych, „trudniejszy do zrozumienia” jest subiektywny i zależy od pierwszego języka, którego się uczysz.
NullUserException,
1
@NullUserException: Sugeruje to, abyś ostrożnie wybrał swój pierwszy język, aby zmaksymalizować łatwość rozumienia innych. Taki jest cel programu, aw szczególności książki SICP.
Ira Baxter,
6

Języki opisu sprzętu są językami programowania, ale pod względem koncepcyjnym są bardzo różne. Spróbuj VHDL lub Verilog dla rozmiaru. Są wspólne dla programowania układów FPGA. (Ok, więc nie są to procesory, ale są to urządzenia obliczeniowe ogólnego przeznaczenia. I takie powinny być uważane za prawidłowy sprzęt do zagadnień informatycznych.) Musisz jawnie sprawić, by coś wystąpiło szeregowo. To zupełnie inny model. Pomyśleliście o rzeczach występujących równolegle jako reguła, a nie wyjątek. Pętle w Verilog rozwijają się w sprzęt równoległy. Zatem „oczekiwane” zachowanie może nie być zgodne z oczekiwaniami.

NoMoreZealots
źródło
Trafne spostrzeżenie. Sprawdzę Verilog / VHDL.
Zawsze myślałem, że konwencjonalne języki programowania były po prostu kiepskimi sposobami do kodowania programów, które były naturalnie równoległe, takich jak VHDL. Kiedy zaczynasz jako projektant sprzętu, ten fragment o wszystkim, co dzieje się w sposób seryjny, wydaje się niezwykle niezdarny. (Uczymy ludzi programowania niewłaściwych języków jako ich pierwszego języka: powinien to być Verilog!).
Ira Baxter,
4

Zależy, co rozumiesz przez „w zasadzie”. Wszystkie języki o dowolnej elastyczności są kompletne. W tym sensie: tak, wszystkie są zasadniczo takie same.

Na niskim poziomie wszystkie wykonują podobne sekwencje operacji, a wszystkie elementy systemu Windows, Linux i (najnowszego) OS X działają na procesorach zgodnych z Intelem przy użyciu tych samych zestawów instrukcji. W ten sposób są one w zasadzie takie same.

Zdaję sobie sprawę z tego, że zdefiniowałeś „zasadniczo” w swoim pytaniu, ale aby naprawdę na nie odpowiedzieć, ta definicja będzie musiała być znacznie bardziej dopracowana. Pod wieloma względami wszystkie są do siebie podobne. Pod wieloma względami są różne. Zbyt łatwo jest powiedzieć „to zależy”. Jeśli przyjmiesz skrajność, pytanie prawdopodobnie nie odpowie na to, na co masz zamiar, więc to, gdzie ta linia jest narysowana, ma kluczowe znaczenie dla udzielenia odpowiedzi na twoje pytanie tak, jak chcesz.

Dina
źródło
3

Powiedziałbym, że język koduje znaczenie. Jeśli znaczenie ma jakiś sens w jakimś kontekście, wówczas wszystkie języki, które mogłyby je wyrazić, można uznać za równoważne, ograniczone przez znaczenie i kontekst.

Jeśli ograniczysz ten kontekst do standardowej maszyny von Neumanna, to można by powiedzieć, że źródłem obliczeń zmiany pamięci i obliczeń w jednostce centralnej jest pochodzenie - i być może jedyne znaczenie, które mają wszystkie języki. Wszystkie inne rzeczy są na nich zbudowane abstrakcją.

Preet Sangha
źródło
1
John von Neumann. I NIE jest wymawiane jak „newman”, bardziej jak „noyman”.
Dzięki za korektę - mówię tak, jak powiedziałeś.
Preet Sangha,
Gdy ktoś zaproponuje poprawkę, możesz po prostu edytować swój wpis, aby go odzwierciedlić.
Phil Miller,
2

Języki programowania są również narzędziami do myślenia. Z innej perspektywy myślenia niektóre problemy znikają lub są przekształcane w inny, łatwiejszy w zarządzaniu (na przykład wiele wzorców projektowych w stylu C ++ po prostu znika, gdy myślisz w Lisp (patrz na przykład prezentacja Petera Norvika ), a Erlang uwalnia cię od myślenia niektórych niskopoziomowych współbieżnych lub rozproszonych konstrukcji obliczeniowych i pozwala skoncentrować się na logice aplikacji).

Zauważ jednak, że czasami „nowe” paradygmaty można częściowo zastosować do „starszych” języków programowania, co wyjaśnia, dlaczego na przykład mamy książki uczące programowania funkcjonalnego dla programistów Java . Ale natywne wspieranie i integrowanie silniejszego paradygmatu na poziomie językowym umożliwia bardziej naturalne zastosowanie paradygmatu (i w konsekwencji uniemożliwia zrozumienie programów w języku obsługującym nieznany paradygmat, jak sugerują inne odpowiedzi - @Ira Baxter wymienia języki nieprocesowe i @kwatford w odniesieniu do Paula Grahama ).

FooF
źródło
2
+++++++[>+++++++++++<-]>+.<+++++++++++[>+++<-]>.>>+++++++[>++++++<-]>++++.

Na najniższym poziomie każdy język programowania jest „taki sam”, ale to nie znaczy, że są one takie same na poziomie, na którym faktycznie się komunikujesz. Są dla ciebie abstrakcyjnymi problemami; to nie znaczy, że abstrakcyjnie te same problemy lub że każdy problem w ten sam sposób.

asthasr
źródło
1

Dojrzałe języki mają zazwyczaj kilka celów i dokonują kompromisów, w których poświęcają jedną rzecz dla drugiej. Języka ogólnego przeznaczenia można używać do wszystkiego, ale żaden język nie może przodować w każdej dziedzinie. Kilka przykładów:

C stara się być idealnym językiem programowania systemów. W tym celu poświęca czytelność i bezpieczeństwo kontroli niskiego poziomu i prędkości.

Python ma być idealnym językiem skryptowym. W tym celu poświęca szybkość i weryfikowalność dla produktywności i przenośności.

Haskell stara się być bezpiecznym, matematycznie czystym językiem. W tym celu poświęca możliwość uczenia się i konwencję w celu weryfikacji i wiarygodności.

Te poświęcenia i korzyści mają ogromną różnicę w języku. Tak, większość języków programowania może być używana do wszystkiego, co może być wykonane przez komputer, ale żaden z tych samych języków nie powinien być używany do wszystkiego. Wszystkie powyższe języki to te, które wybrałbym do niektórych zadań, ale nie do innych. Gdybym programował system operacyjny, wybrałbym C. Gdybym pisał backend dla strony internetowej, użyłbym Pythona. A gdybym pisał system finansowy, użyłbym Haskell.

Ostatecznie wybór programisty jest tym, co jest właściwym narzędziem do pracy.

Imagist
źródło