Chciałbym odnieść się do pomysłu wielu plakatów, że taki język byłby „bezużyteczny”. Być może pisanie ręczne z myślą o rozwiązaniu określonego zadania byłoby bezużyteczne dla ludzi. Jednak pomimo tego, że jest to większość przypadków użycia dla języków programowania, z pewnością nie jest to jedyny przypadek użycia. Przypomina się kilka przypadków użycia, w których taki język jest przydatny, i możemy poszukać w tych polach przykładów takich języków.
Po pierwsze aluzja Cort Ammon do genetyki jest na miejscu: przekształcenie programu w pytaniu (podstawiając )
za 5
) może być postrzegane jako mutacji . Ten rodzaj manipulacji jest powszechny w dziedzinie obliczeń ewolucyjnych ; w szczególności algorytmy genetyczne wykonują takie transformacje na łańcuchach , podczas gdy programowanie genetyczne przekształca programy . W obu przypadkach zwykle chcemy przypisać znaczenie każdej możliwości, ponieważ spowoduje to utworzenie najbardziej kompaktowej przestrzeni wyszukiwania.
Algorytmy genetyczne opierają się na jakiejś funkcji oceny ciągów; jeśli używamy interpretera języka programowania jako naszej funkcji oceny, mamy scenariusz, w którym użyteczny jest język programowania, który nadaje znaczenie wszystkim możliwym ciągom znaków. W programowaniu genetycznym zakłada się, że naszą funkcją oceny jest tłumacz języka programowania, ale możemy wybrać różne reprezentacje dla naszych programów; na przykład wiele systemów działa na abstrakcyjnych drzewach składniowych. Jeśli wybierzemy ciągi jako naszą reprezentację, wówczas odzyskamy ten sam scenariusz, co w przypadku algorytmów genetycznych.
Inną sytuacją, w której możemy chcieć, aby każdy ciąg znaków był poprawnym programem, jest liczenie programów. Jest to związane z odrzuceniem wspomnianym przez CodesInChaos, ale możemy preferować operowanie na ciągach zamiast liczb naturalnych z kilku powodów:
- Jeśli w języku jest jakaś struktura, np. możemy przypisać znaczenie podciąganiom, które mogą zostać utracone podczas tłumaczenia na liczby naturalne. W takim przypadku możemy preferować użycie łańcuchów, aby lokalnie uzasadniać i przekształcać podłańcuchy, zamiast reprezentować cały program jako liczbę. Jest to analogiczne do tego, w jaki sposób wolelibyśmy używać operacji bitowych na wyrażeniach int zamiast wyrażeń arytmetycznych, gdy każdy bit ma indywidualne znaczenie. Jest to zasadniczo uogólnienie scenariusza ewolucyjnego.
- Możemy chcieć generować programy na żądanie; na przykład możemy rozpocząć wykonywanie programu, który jest całkowicie nieokreślony, i generować (np. losowo) poszczególne instrukcje (np. znaki), gdy / jeśli wskaźnik instrukcji do nich dotrze. Jest to powszechne w algorytmicznej teorii informacji, gdzie program jest taśmą maszynową Turinga, a celem jest scharakteryzowanie zachowania losowo generowanych programów. Na przykład możemy sformułować Solomonoff przed dowolnymi ciągami jako prawdopodobieństwo, że uniwersalna maszyna Turinga z losową taśmą wyśle ten ciąg.
Pod względem języków przykładowych wiele ewolucyjnych systemów obliczeniowych opiera się na językach stosu, takich jak rodzina Push . Umożliwiają one dowolne strumienie tokenów (które moglibyśmy reprezentować jako pojedyncze postacie). Czasami (podobnie jak w przykładzie Brainfuck BrainSlugs83) istnieją ograniczenia dotyczące równoważenia nawiasów; możemy jednak powiązać to z programami samoograniczającymi się , ponieważ taki ciąg znaków [
może nie być poprawnym programem , ale jest prawidłowym prefiksem programu . Jeśli wyobrażamy sobie kompilator / interpreter odczytujący kod źródłowy ze standardowego wejścia, wówczas nie odrzuci takiego ciągu [
, po prostu poczeka na więcej danych wejściowych przed kontynuowaniem.
Języki takie jak Binary Combinatory Logic i Binary Lambda Calculus powstały bezpośrednio z pracy nad algorytmiczną teorią informacji, np. z http://tromp.github.io/cl/cl.html
Ten projekt minimalistycznego uniwersalnego komputera był motywowany moim pragnieniem wymyślenia konkretnej definicji złożoności Kołmogorowa, która bada losowość poszczególnych obiektów.
You are a bimbo.