Trudno jest odpowiedzieć na pytania typu „jest X Y ”, jeśli uczestnicy ruchu debata różnych definicji X i Y . Możliwe, że w przypadku niektórych definicji odpowiedź brzmi „tak”, a w przypadku niektórych definicji odpowiedź brzmi „nie”. Zwłaszcza jeśli odpowiedź zależy od szczegółów technicznych, w których różne definicje są różne. Również ta dyskusja zawiera pewne dezinformacje, więc prosimy o cierpliwość przy dłuższej odpowiedzi.
Co rozumiemy przez „ język programowania ”?
Prostą odpowiedzią może być „język używany do tworzenia programów”. Jasne, ale: jakie programy? Co powiesz na język, który może być użyty do tworzenia niektórych rodzajów programów, ale nie innych rodzajów programów? Oto dwa konkretne przykłady ilustrujące skrajne przypadki:
1) Wyimaginowany język o nazwie M działa w następujący sposób: Jeśli program zawiera pojedynczą literę „m”, tworzy grę Saper. Cała reszta to błąd składniowy.
Intuicyjnie nie to rozumiemy przez „język programowania”. Ale dział marketingu M może argumentować, że technicznie spełnia definicję, ponieważ można go użyć do stworzenia programu. Jasne, kompilator robi dla ciebie pewne krytyczne części, ale to właśnie robią kompilatory, prawda? Kompilator języka C tłumaczy również kilka prostych słów na dziesiątki instrukcji procesora. Kompilator M idzie jeszcze dalej i jeszcze bardziej upraszcza pracę.
2) Jeśli zainstalujesz oryginalną wersję słynnego Turbo Pascal, możesz pisać wiele rodzajów programów. Nie można jednak napisać gry, która działa w przeglądarce internetowej, ponieważ niezbędnego interfejsu API po prostu nie ma.
Więc co dokładnie sprawia, że Turbo Pascal jest językiem programowania, ale M go nie ma? Krótko mówiąc, możesz zrobić więcej w Pascalu niż w M. Ale wyobraź sobie, że mamy M.NET, który tworzy grę Saper w przeglądarce internetowej. Więc teraz mamy coś, co Pascal może zrobić, a M.NET nie, ale mamy też coś, co M.NET może zrobić, a Pascal nie. Dlaczego powinniśmy uważać zalety Pascala za ważne, a zalety M.NET nie mają znaczenia?
Odpowiedź jest taka, że możesz pisać wszelkiego rodzaju algorytmy w Pascal, ale nie możesz pisać algorytmów w M lub M.NET. Jasne, M kompiluje twoje polecenie „m”, a C kompiluje twoje polecenie „strcmp”. Ale możesz umieścić „strcmp” w większym kontekście, na przykład porównać dwa pliki wiersz po wierszu lub odczytać tysiące ciągów i posortować je alfabetycznie lub… cóż, miliony innych rzeczy. I właśnie ta umiejętność korzystania z danych poleceń w dowolnym algorytmie stanowi istotę języka programowania.
Czym dokładnie jest algorytm, a co ważniejsze, czym jest „dowolny algorytm”? W informatyce używamy słów Turing-complete . Chodzi o to, że istnieje zestaw języków komputerowych, w których każdy z nich jest w stanie zasymulować wszystkie z nich. Jednym z tych języków jest maszyna Turinga, dlatego tak się je nazywa. Jest tam Pascal, jest C, jest Java, jest Python, jest Lisp, jest Smalltalk, jest nawet XSLT. Nasz hipotetyczny M i M.NET są nie istnieje. Możesz dowiedzieć się o tym więcej na dowolnym uniwersytecie, oferując porządny kurs informatyki, ale chodzi o to, że język kompletny Turinga może zrobić wszystkoco może zrobić inny język Turinga, pod warunkiem, że zapewnisz im minimum niezbędnego API. (Jeśli przekażesz Pascalowi interfejs API przeglądarki internetowej, możesz tworzyć wszelkiego rodzaju gry w przeglądarce internetowej. Jeśli przekażesz interfejs API przeglądarki internetowej M, nadal możesz utworzyć Saper). Możemy powiedzieć metaforycznie, że jeśli usuwasz wszystkie interfejsy API z języka programowania, ważne jest to, co pozostaje.
Co rozumiemy przez „ wyrażenia regularne ”?
Różne języki programowania wdrażają je nieco inaczej. Ale oryginalny pomysł polegał na tym, że wyrażenia regularne wyrażają tak zwane języki regularne . Zauważ, że nie mówimy tutaj o językach programowania, ale o (pseudo-) językach ludzkich. Wyobraź sobie, że znajdujesz jakieś egzotyczne plemię mówiące językiem składającym się wyłącznie ze słów „ba”, „baba”, „bababa” i tak dalej. Możesz opisać ten język werbalnie jako „sylabę„ ba ”powtarzaną jeden lub więcej razy” lub używając wyrażenia regularnego jako „(ba) +”.
Wyrażenia regularne powinny wyrażać: „nic”, „ta litera”, „to, po którym następuje”, „to lub tamto”, „to, powtarzane jeden lub więcej razy”, i „nie to”. - To jest definicja matematyczna . Wszystko inne to tylko wygodny skrót zbudowany z poprzednich komponentów. Na przykład „to, powtórzono dwa lub trzy razy” można przetłumaczyć jako „to, a następnie to, a następnie (to lub nic)”, ale wygodniej byłoby napisać „ba {2,3}” niż „baba (ba)? ”.
W prawdziwym życiu typowa implementacja „wyrażeń regularnych” implementuje więcej niż to. Na przykład, używając definicji matematycznej, języka „aba”, „aabaa”, „aaabaaa” itd. - dowolna liczba „a”, po których następuje „b”, a po nim ta sama liczba „a” „s - nie jest zwykłym językiem. Jednak wiele „wyrażeń regularnych” używanych dzisiaj może je wykryć, wykorzystując dodatkową koncepcję „tego samego, co znaleźliśmy wcześniej”, zapisaną jako „(a +) b \ 1”. Korzystając z tej dodatkowej koncepcji, możemy robić fajne rzeczy, na przykład wykrywać słowa składające się z pierwszej liczby liter. Mimo to nie możemy wykonać żadnego algorytmu ... dla wyjaśnienia, dlaczego,
Wracając do pierwotnego tematu: czy wyrażenia regularne (zdefiniowane albo jako: wyrażenia opisujące języki regularne w hierarchii Chomsky'ego, czy jako: poprzednie, plus operacja \ 1) są językiem programowania (zdefiniowanym jako: Turing-complete)? Odpowiedź brzmi nie . Nie, nie możesz zaimplementować żadnego algorytmu za pomocą wyrażeń regularnych, a możliwość zaimplementowania dowolnego algorytmu jest tym, co ludzie studiujący informatykę zazwyczaj rozumieją jako esencję języka programowania.
Oczywiście każdy może zmienić odpowiedź, nalegając na inną definicję . Jak napisałem na początku, szczegóły techniczne są tutaj ważne. Jeśli źle je zrozumiesz, otrzymasz złą odpowiedź.
A jeśli nie zainteresowani szczegółami technicznymi, odpowiedź może być: można używać wyrażeń regularnych (i nic innego), aby program? Nie. Dlaczego więc nazywać to językiem programowania? (Jednak taka odpowiedź została tutaj pobrana i usunięta, dlatego napisałem tę dłuższą wersję).
EDYCJA: Ponadto każdy może stworzyć bibliotekę implementującą swój nowy wariant „wyrażeń regularnych” z kilkoma dodanymi nowymi funkcjami. W pewnym momencie nowe funkcje mogą wystarczyć, aby cały system stał się kompletny w Turingu. Trywialnym przykładem byłoby osadzenie języka pełnego Turinga przy użyciu nowej składni; ale może się to zdarzyć mniej oczywiste. Może to już się stało.