Plankalkül – język, który wyprzedził swoje czasy

Był rok 1945, kiedy Konrad Zuse, niemiecki inżynier, kończył właśnie pisać swój szkic na temat języka o tajemniczo brzmiącej nazwie Plankalkül. Przez ostatnie lata Zuse zajmował się projektowaniem maszyn liczących, spośród których największym osiągnięciem było urządzenie nazwane Z3, obecnie uznawane za pierwszy na świecie programowalny komputer. Podczas prac nad swoimi wynalazkami zauważył potrzebę takiego sposobu komunikacji z komputerem, który umożliwiałby przekazywanie mu do rozwiązania zróżnicowanych problemów matematycznych.

Odpowiedzią na to było stworzenie języka programowania Plankalkül, który w założeniu miał pozwolić na formułowanie programów do obliczeń inżynierskich w postaci, która jest przyjazna i bardziej zrozumiała dla użytkownika niż posługiwanie się niskopoziomowymi rejestrami. Chociaż ostatecznie język ten nie został nigdy w pełni zaimplementowany, to jego szczegółowo opisana przez wynalazcę koncepcja stanowi jedną z ważniejszych w historii informatyki. Niestety należy też ona do grona tych zapomnianych, a fakt, że czasami narodzin pierwszego wysokopoziomowego (nie da się bowiem ukryć, że programowanie w Plankalkülu miało abstrahować od wszelkich szczegółów sprzętowych) języka programowania była pierwsza połowa lat 40. XX wieku wciąż wywołuje zdziwienie u wielu osób. Przyjrzyjmy się więc nieco bliżej niesamowitemu pomysłowi Konrada Zuse.

Dwuwymiarowe plany obliczeń

Nazwa Plankalkül oznacza w dosłownym tłumaczeniu „formalny system planowania” i trzeba przyznać, że bardzo dobrze pasuje ona do tego, jak wyglądało tworzenie programów w tym języku. Sam Zuse określał je mianem Rechenpläne, czyli planów obliczeń. Każdy program definiowany jest za pomocą planów, które składają się z dwóch części:

  • Randauszug – nagłówka, określającego liczbę i typ parametrów wejściowych oraz wyjściowych. Nie ma tu jednak pola do popisu jeśli chodzi o nadawanie zmiennym odpowiednich nazw, bowiem język z góry je narzuca. Parametry wejściowe są określane jako V0, V1,…, Vn, natomiast zwracane wartości trafiają do zmiennych R0, R1,…, Rm (widzimy już zatem, że parametrów wyjściowych może być więcej niż jeden)
  • Sekcji zawierającej właściwą logikę i obliczenia. Wywoływać w niej można inne plany, ale niemożliwa jest rekurencja. Dodatkowe zmienne pomocnicze nazywane są Z0,…,Zn (od słowa Zwischenwerte – wartości pośrednie), a ich deklarowanie następuje dopiero w miejscu ich użycia.

Fragment takiego właśnie planu obliczeń stworzonego w języku Plankalkül znajduje się poniżej (źródło: R. Rojas, Plankalkül, 1999):

 

Już na pierwszy rzut oka widać tu jedną z dziwniejszych cech tego języka, a mianowicie dwuwymiarową notację, która wydaje się nieco skomplikowana, a z pewnością nieoczywista. Rozjaśnieniem owego zapisu może być przedstawienie go w postaci normalnego pseudokodu:

Krótka chwila analizy i od razu wiadomo, że:

  • liczby w wierszu V stanowią integralną część nazw zmiennych (czyli w tym przypadku mamy V1, V2 oraz Z1)
  • liczby w wierszu K oznaczają indeks (komponent), do którego się odnosimy
  • operacja przypisania oznaczana jest za pomocą symbolu ⇒

Zagadkowe wciąż pozostają za to cyfry w ostatniej linii (S). Co kryje się za 5.8.0? Otóż jest to po prostu typ konkretnej zmiennej. Chociaż może wcale nie po prostu, gdyż i w tym aspekcie Plankalkül zaskakuje dość niecodziennym podejściem.

Typy danych

Jedynym prymitywnym typem danych jest bit, oznaczany liczbą 0 i nazywany Ja-Nein-Werte (wartościami tak-nie). Stanowi on bazę do tworzenia bardziej złożonych typów. Na przykład chcąc operować na zmiennej przechowującej jeden bajt danych posłużymy się typem 8 x 0, alternatywnie zapisywanym jako 8.0 (Zuse dopuszcza stosowanie kilku różnych notacji). Oczywiście równie dobrze możemy w ten sposób stworzyć sobie typ 3-bitowy (3.0) lub 12-bitowy (12.0). Ale to nie koniec, bowiem tak zdefiniowane typy podlegają dalszej rozbudowie. Pisząc 5.8.0 uzyskamy więc 5-elementową tablicę bajtów, zaś zapis (2.0, 4.0) oznacza krotkę składającą się z wartości 2-bitowej oraz 4-bitowej. W swoich pracach Zuse podaje też przykłady programów, w których używa jeszcze innych typów, np. liczbą 8 koduje on typ przechowujący liczbę naturalną, a ułamek oznacza typem 12. Warto jednak pamiętać, że są to bardziej szkice niż spójna i szczegółowa specyfikacja.

Funkcjonalności języka

Pomijając niestandardową formę zapisu programów oraz interesujący system typów danych, Plankalkül jawi się jako język posiadający większość cech współczesnych języków programowania. Istnieją w nim oczywiście instrukcje warunkowe (oznaczane przez operator strzałki z kropką na dole), można posługiwać się pętlami (zostało ich nawet pomyślanych aż 6 rodzajów – reprezentowane są przez symbol W), a wewnątrz planów programista może używać operatorów logiki predykatów (np. kwantyfikatora ogólnego) oraz operatorów związanych z działaniami na listach i zbiorach.

Niektóre z opracowanych koncepcji są o tyle zadziwiające, że nawet wiele późniejszych języków było ich pozbawionych. Wśród tego typu elementów wymienić można ideę funkcji szablonowych, które można dostarczać jako parametry wejściowe do planów, oraz symbol Fin. Jest on stosowany wewnątrz pętli, a jego działanie porównać można do instrukcji opuszczenia reprezentowanej zwykle przez słowo kluczowe break. Zaskoczeniem jest tu jednak fakt, że aby wyjść z pętli wewnętrznej oraz zewnętrznej wystarczy zastosować symbol Fin2. Co ciekawe, Zuse proponuje, by w analogiczny sposób używać oznaczenia Finn, choć obawiam się, że wiele zagnieżdżonych pętli nie wyglądałoby zbyt przejrzyście w Plankalkülowym kodzie.

Implementacje

Na szczęście Plankalkül nie został zupełnie zapomniany i co jakiś czas pojawiają się próby implementacji tego historycznego języka. Oczywiście nikt nie sugeruje, że może być to technologia wykorzystywana gdziekolwiek komercyjnie, ale dzięki swoim unikatowym cechom z pewnością jest to język, z którym zmierzenie się jest ciekawym treningiem intelektualnym. Pierwszym wyzwaniem, z którym muszą poradzić sobie programiści pragnący stworzyć kompilator Plankalküla, jest kwestia zaproponowanej przez Konrada Zuse dwuwymiarowej notacji. Najpopularniejszym podejściem w tym względzie jest zaprojektowanie notacji linearnej, która jednocześnie pozwoli na zachowanie charakterystycznych elementów języka (typy powiązane z każdym użyciem zmiennej) oraz na pisanie kodu w bardziej naturalny sposób. Z takiego właśnie założenia wyszedł m.in. Jimmo Barrion Petisme, twórca implementacji o nazwie linPlank (powstałej w roku 2004), która nie jest wprawdzie pełnym odwzorowaniem wszystkich funkcjonalności języka, ale stanowi swego rodzaju proof of concept. Dwuwymiarowy plan zawierający indeksy i numery komponentów poszczególnych zmiennych może w linPlankowej notacji wyglądać np. w następujący sposób:

Nieco dalej poszli twórcy pierwszej implementacji Plankalküla (Raúl Rojas, Cüneyt Göktekin, Gerald Friedland oraz Mike Krüger), noszącej nazwę Plankalkül 2000 i uruchomionej w 55. rocznicę powstania języka. Postanowili oni udostępnić nie tylko opcję posługiwania się notacją linearną, ale też wizualny edytor, pozwalający na posługiwanie się oryginalnym macierzowym zapisem. Warto zauważyć, że taki sposób programowania cechuje się ochroną użytkownika przed możliwością popełnienia jakichkolwiek błędów składniowych w rozwijanym programie (ale oczywiście nie zabezpiecza przed pomyłkami semantycznymi). Niestety projekt Plankalkül 2000 również nie implementuje wszystkich funkcjonalności języka, pomijając między innymi obsługę operacji na listach, a także definiowanie list o zmiennym rozmiarze. Wydaje się, że obecnie nie jest już w Internecie dostępny kompilator Plankalkül 2000Niegdyś znajdował się on na tej stronie, ale aktualnie nie działa.

Aplet z edytorem Plankalkul 2000

Jeśli chodzi o szczegóły techniczne powyższych implementacji, to w obu przypadkach autorzy posłużyli się Javą. Podczas tworzenia linPlank język ten został wykorzystany do zaprogramowania interpretera. Jak można dowiedzieć się z opisu projektu, jego twórca użył takich narzędzi jak Java CUP w celu zbudowania analizatora składniowego oraz JLex do analizatora leksykalnego. Z kolei w Plankalkül 2000 w Javie napisane zostało całe środowisko uruchomieniowe, zaś parser powstał z wykorzystaniem narzędzia Cocktail.

Co poszło nie tak?

Skoro Plankalkül był tak innowacyjny i przełomowy, to dlaczego nie odniósł sukcesu? Powodów takiego stanu rzeczy jest kilka. W wielu publikacjach podkreślane jest, że prace Konrada Zuse zawierają wiele błędów i niespójności – zarówno w przykładach programów, jak i w samej dokumentacji języka. Nie wydaje mi się jednak, aby było to główną przyczyną porażki – wszak każdy raczkujący projekt skazany jest na pewne choroby wieku dziecięcego. Kolejną tezą jest, jakoby Zuse podszedł do tematu zbyt ambitnie jak na tamte czasy. Czasy, w których właściwie nie istniała jeszcze teoria języków programowania, a projektowanie parserów i kompilatorów było w powijakach. Plankalkül ze swoją skomplikowaną notacją i dziwnym systemem typów nie był najprostszym do implementacji językiem. Co więcej, w roku 1945 środowisko naukowców zajmujących się komputerami po prostu nie dostrzegało jeszcze potrzeby języków programowania wysokiego poziomu. Możliwe, że gdyby nowatorskie pomysły Zuse zostały opublikowane kilkanaście lat później, padłyby na bardziej podatny grunt.

Myślę, że w programistycznej społeczności wiedza o istnieniu języka Plankalkül jest potrzebna i wartościowa. Jest to bowiem tak naprawdę świadomość tego, że historia języków programowania rozpoczęła się z przytupem i ambicją. Plankalkül  jest przykładem idei, która nie została wcielona w życie, ale która z pewnością odcisnęła swoje piętno w historii informatyki. Gdybym miał snuć dalszy ciąg tej opowieści, to powiedziałbym, że w przyszłości język ten niechybnie stanie się dla kogoś bodźcem do stworzenia technologii wychodzącej poza utarte schematy. Bo czy nie tego własnie potrzebujemy teraz w programowaniu?

Kalendarium

  • 1942-1945 – Konrad Zuse prowadzi prace nad językiem Plankalkül. Przygotowuje dystertację doktorską (ostatecznie nie została złożona), kontynuacją której było stworzenie szkicu języka.
  • 1946 – Zuse kończy pisać pierwszą książkę poświęconą nowemu językowi, jednak nie decyduje się na jej wydanie.
  • 1948 – Twórca Plankalküla publikuje artykuł w „Archiv der Mathematik”, nie przynosi on większego rozgłosu.
  • 1957 – Powstaje Fortran, pierwszy powszechnie używany język wysokiego poziomu.
  • 1972 – F.L. Bauer i H. Wössner wydają książkę The „Plankalkül” of Konrad Zuse: A Forerunner of Today’s Programming Languages.
  • 1975 – Pierwsza próba implementacji języka przez Joachima Hohmanna.
  • 2000 – Stworzenie edytora i kompilatora Plankalkül 2000.
  • 2004 – Implementacja linPlank.

 

Fragment publikacji „Der Plankalkül” K. Zuse wydanej w roku 1972

 

Źródła