We wcześniejszych felietonach tego cyklu (dostępnych w internecie) opisałem wiele języków programowania, które dawały programistom możliwości skutecznego opisywania różnych programów i tworzenia nawet bardzo zaawansowanych algorytmów. Języki te były jednak tak projektowane, żeby zapewnić łatwość opisywania operacji wykonywanych na liczbach. Takie bowiem były wtedy jedyne zastosowania komputerów: wprowadzano do nich dane w postaci liczb i oczekiwano wyników także w postaci liczb. Najpierw były to obliczenia dotyczące strzelania z armat, potem – gospodarki i zarządzania, następnie zaś inżynierskie i naukowe. Ale zawsze sprowadzały się one do obliczeń numerycznych.

Zalety obliczeń symbolicznych

Obliczenia numeryczne są potrzebne, ale ich wyniki mają zawsze bardzo konkretny i ograniczony zakres zastosowań. Jeśli rozważymy przykład obliczeń numerycznych, np. 3 x 6 = 18, to pozwoli on na przewidzenie, ile będziemy musieli zapłacić w kasie sklepu, jeśli w koszyku mamy 3 kartony soku po 6 zł za jeden karton. Ale nic więcej! Żadnych wniosków z tego wyciągnąć nie można. Natomiast jeśli rozważymy zapis symboliczny: m x a = F, to możliwe jest mnóstwo wniosków. Powyższy symboliczny zapis znany jest jako prawo dynamiki Newtona. Jeśli przyjmiemy, że „m” oznacza masę, „a” przyspieszenie, „F” zaś to wartość siły – to możemy go użyć do różnego rozumowania. Rozumowania możliwego do przeprowadzenia także automatycznie przez komputer! Przykładowo możemy się dowiedzieć, jaką siłę „F” musi rozwijać silnik rakiety, jeśli ma ona wynieść w kosmos satelitę o masie „m” i nadać mu przyspieszenie „a” potrzebne do wprowadzenia go na orbitę.

Albo gdy znajomy przechwala się: „Mój samochód rozpędza się w 3 sekundy do setki!”, to wystarczy dowiedzieć się, jaką masę „m” ma ów samochód i jaką siłę „F” jest w stanie wytworzyć jego motor – żeby dowiedzieć się, jakie przyspieszenie „a” może ów samochód naprawdę osiągnąć.

Żartem można tego symbolicznego zapisu użyć do odpowiedzi na pytanie: „Jak ciężki musiał być miecz katowski, którym ścięto głowę Marii Stuart?”. Wiemy, do jakiego przyspieszenia „a” zdolna jest ręka człowieka, wiemy też, jaka siła „F” potrzebna jest do obcięcia głowy – możemy więc dowiedzieć się, jaką masę „m” musiał mieć ów miecz.

Skupiliśmy się na rozważaniu przydatności symbolicznego zapisu m x a = F przy założeniu interpretacji użytych symboli zgodnie z prawem dynamiki Newtona. Ale symbole nie mają na stałe przywiązanego znaczenia, można więc przyjąć, że „m” to szerokość działki, „a” to jej długość, a „F” to powierzchnia. Wtedy możemy na przykład dowiedzieć się, jak szeroką działkę musimy kupić (m), skoro jej długość (a) jest narzucona przez płynącą rzekę, a dla uzyskania pozwolenia na budowę potrzebujmy powierzchni F. Możliwości jest mnóstwo!

Obliczenia symboliczne i komputery

Mam nadzieję, że nie muszę mnożyć dalszych przykładów, żeby przekonać państwa, że obliczenia symboliczne pozwalają na znacznie więcej niż obliczenia numeryczne. Podobne rozumowania prowadzili pierwsi informatycy zmierzający do stworzenia podstaw sztucznej inteligencji. Komputer umiejący wykonać działanie 3 x 6 = 18 jest zwykłym liczydłem (tylko bardzo szybkim). Natomiast komputer umiejący wyciągać wnioski z zapisu m x a = F jest narzędziem wykazującym cechy inteligentnego działania. Tylko do tego celu trzeba go odpowiednio zaprogramować, a pierwszym językiem, który pozwalał pisać takie programy, był LISP.

Nazwa LISP pochodzi od „LISt Processing”, co sygnalizuje, że podstawową strukturą danych w tym języku programowania jest lista. Zastosowanie list (zamiast używanych w innych językach programowania tablic i rekordów) było trafnym pomysłem, bo właśnie w tej formie wygodnie jest zapisywać formuły obliczeń symbolicznych. Pomysłodawcą języka LISP był John McCarthy, profesor MIT. Koncepcję zasadniczych elementów tego języka McCarthy zdefiniował w 1958 r., LISP (do dzisiaj używany!) jest więc jednym z najstarszych języków programowania. Swą koncepcję McCarthy opublikował w 1960 r. w artykule zatytułowanym „Rekursywne funkcje wyrażeń symbolicznych i ich maszynowe obliczanie, część I”. Przyznacie państwo chyba, że od takiego tytułu normalnego człowieka mogą rozboleć zęby? McCarthy chyba też tak uznał, bo druga część tego artykułu nigdy się nie ukazała.

LISP powstał jako teoretyczna koncepcja. Nawet sam McCarthy nie wierzył, że przełoży się to na praktykę. Tymczasem student McCarthy’ego, Steve Russell, zaimplementował LISP na komputerze IBM 704 i pokazał, że to naprawdę działa! Rozwiązanie Russela pozwalało na interpretację LISP-u za pomocą funkcji eval, czyli w istocie było tylko atrapą języka programowania, ale działało i przekonało niedowiarków, że to ma sens. W rezultacie w 1962 r. powstał pierwszy prawdziwy translator LISP-u. Zbudowali go Tim Hart i Mike Levin. Ciekawostka polegała na tym, że translator LISP-u został napisany w... LISP-ie!

Skrajne oceny

LISP ostro „namieszał” w środowisku informatyków i budził skrajne emocje. Przez długi czas był on jedynym narzędziem informatycznym umożliwiającym programowanie operacji na różnych symbolach, napisach i tekstach, stąd stał się sztandarowym narzędziem dla wszystkich badaczy prowadzących prace związane z powstającą i rozwijającą się sztuczną inteligencją. Na bazie LISP-u w 1970 r. zbudowano narzędzie do tworzenia programów sztucznej inteligencji nazwane Micro-Planner, które z kolei posłużyło Terry’emu Winogradowi do stworzenia w MIT systemu SHRDLU służącego do inteligentnej konwersacji z ludźmi na temat aktywności robota w wyidealizowanym środowisku złożonym z dowolnie rozmieszczanych brył stereometrycznych. Wcześniejsze systemy sztucznej inteligencji działały w sferze czystej abstrakcji, działając na różnych symbolach, co naukowo było wartościowe, ale nie nadawało się do „pokazania”. Dlatego SHRDLU, który pokazywał działania, w 1972 r. był uważany za ogromny sukces sztucznej inteligencji. LISP jako jego fundament informatyczny zyskał wtedy wielu zwolenników.

Powstały liczne wersje języka LISP. W tym burzliwym okresie wyłoniły się dwie gałęzie rozwojowe. Najbardziej rozpowszechniony był Common LISP (w różnych odmianach), ale popularna była także gałąź związana z bardzo „ascetyczną” wersją LISP-u nazywaną Scheme. Wersję tę stworzyli w MIT Guy L. Steele oraz Gerald Sussman. Miała ona wielu zwolenników właśnie dlatego, że zawierała jedynie podstawowe mechanizmy i dawała użytkownikowi dużo swobody w kształtowaniu własnego narzędzia sztucznej inteligencji.

Minęło wiele lat i pozycja LISP-u nie jest już taka jak dawniej, ale warto przypomnieć, że w latach 70. i 80. informatycy tak się nim zachwycali, że wymusili na elektronikach budowę specjalnej odmiany komputerów, tzw. maszyn LISP-owych, które mogły pracować tylko z programami napisanymi w LISP-ie, ale za to bardzo wydajnie (na zwykłych komputerach programy pisane w LISP-ie działały bardzo wolno).

Jednak maszyny LISP-owe po prostu się zestarzały, a ponieważ szybkość normalnych komputerów bardzo wzrosła, ta gałąź sprzętu komputerowego szybko więc obumarła. Ale sam LISP żyje, modernizuje się, przechodzi liczne przeobrażenia i wciąż jest chętnie używany, chociaż tak bardzo różni się od innych języków programowania, że niektórzy informatycy absolutnie go nie tolerowali. Znana jest opinia wybitnego pioniera informatyki Edsgera Dijkstry, który w 1972 r. napisał: „LISP jest najbardziej wyrafinowanym sposobem niewłaściwego używania komputerów”.

Równocześnie wyposażenie w narzędzia do operowania symbolami języków C++ i Java spowodowało spadek zainteresowania LISP-em. Obecnie wielu informatyków ocenia go jako wspaniały, ale już przebrzmiały element historii informatyki. Natomiast „swoje pięć minut” miał potomek LISP-u: język LOGO.

Kilka słów o charakterystyce i historii LOGO

Przeskok od LISP-u do LOGO wydaje się karkołomny. LISP był narzędziem dla najbardziej zaawansowanych informatyków zajmujących się sztuczną inteligencją. Tymczasem język LOGO przeznaczony jest dla dzieci, takich, które stawiają pierwsze kroki w nauce pisania i czytania, i to głównie do tych, które mają trudności z matematyką.

Trudno o większy kontrast! Tymczasem LOGO to jest odpowiednio zaadaptowany LISP. Jego idea narodziła się z fascynacji amerykańskiego informatyka i dydaktyka matematyki Seymoura Paperta pracami szwajcarskiego psychologa i pedagoga Jeana Piageta. Piaget odwoływał się do analogii między uczeniem matematyki i uczeniem obcego języka. Pisał, że chcąc nauczyć młodego Szwajcara języka angielskiego, można – zamiast kazać mu uczyć się słówek i reguł gramatyki – posłać go do Anglii, gdzie na każdym kroku będzie musiał używać angielskich zwrotów i rozumieć angielskie wypowiedzi. Tak samo z uczniem mającym trudności z matematyką. Należy umieścić go w „matematycznej krainie”, gdzie – chcąc cokolwiek osiągnąć – będzie musiał korzystać z matematyki.

Seymour Papert postanowił stworzyć w komputerze ową matematyczną krainę. Przez cztery lata (poczynając od roku 1967) wspólnie z Wallace’em Feurzeigiem i Cynthią Solomon pracowali nad stworzeniem systemu, w którym dzieci – bawiąc się słowami i zdaniami – będą musiały (nieświadomie!) korzystać z matematyki, poznając jej reguły i zasady. Swój system nazwali początkowo Ghost, ale potem przyjęli nazwę LOGO od greckiego słowa „logos”, czyli „słowo” albo „myśl”. W latach 1988–1991 byłem gorliwym propagatorem używania języka LOGO w polskich szkołach do nauczania podstaw myślenia algorytmicznego. Napisałem o tym sporo artykułów i trzy książki. Ale LOGO zagościł w polskich szkołach na krótko – szybko został zastąpiony przez nowocześniejsze narzędzia informatyczne (np. Scratch czy Arduino).

Zresztą twórcy LOGO w Stanach Zjednoczonych też zauważyli, że zabawa słowami i zdaniami nie angażuje wystarczająco uwagi dzieci. W 1969 r. dodali więc do tego języka tzw. grafikę żółwia, która potem tak dalece zdominowała owo symboliczne (oparte na LISP-ie) jądro języka, że wielu osobom LOGO kojarzyło się wyłącznie z rysowaniem obrazków. Ale ta gałąź LOGO nie należy już do tematyki tego felietonu, bo o grafice komputerowej napiszę osobno.

Autor jest profesorem AGH w Krakowie