Indi Informatyk

Pobierz E-book

„Kukiełka Marionetkarza: o byciu ekspertem w programowaniu komputerowym”


MARJONETKA KVKIEŁKARZA

albo

O BYCIU EKſPERTEM
W ZAUTOMATYZOWANYM
PRZETWARZANIU DANYCH
ZA POMOCĄ PROGRAMOWANYA
MASZYN KALKULUJĄCYCH

F.N.


CAPUT I
NARODZINY TYRANII
Z DUCHA SPRAWCZOŚCI

Kiedy zaczynałem swoją pierwszą pracę jako programista, najbardziej popularnym kalkulatorem w naszym kraju była Wisła 64. Posiadała ona zawrotne 65536 adresowalnych rejestrów pamięciowych oraz jednostkę arytmetyczno-logiczną wspierającą operacje na 16-cyfrowych słowach binarnych. Model programowy był wyjątkowo przyjazny, ponieważ dla niemal wszystkich operacji adres rejestru danych był kodowany w ostatnich dwóch oktetach instrukcji. Był to dramatyczny przeskok względem kalkulatora Orzeł 8, który dominował tuż przed Wisłą. Mimo 8-cyfrowych binarnych operacji arytmetycznych Orzeł umożliwiał adresowanie 16384 oktetów pamięci, ale opierało się to na skomplikowanym systemie banków pamięci. Dla starych wyg Orła, którzy opanowali jego model, ta zmiana faworyta była niemal jak śmierć przyjaciela. Koniec końców otrząsnęli się oni z żałoby i zaczęli wykorzystywać potencjał nowej maszyny. Miałem to szczęście, że wydział na którym studiowałem matematykę stosowaną ze specjalizacją w systemach cyfrowych zdążył zaopatrzyć się w Wisłę 64, gdy byłem na ostatnim roku mojego programu. Dzięki czemu udało mi się skosztować nieco świeżonki przed wylądowaniem na rynku pracy.
Co prawda moim szczytem wykorzystania tego systemu było rysowanie drzewek w konsoli terminala. Uczelniani operatorzy, którym donosiłem karty z wyperforowanym programem, sarkastycznie pytali, czy stworzyłem nowy program albo znowu jest to tylko rysowanie Fryckowych krzaków. Żółć, która mnie od tego zalewała, odparowywała w kontakcie z entuzjazmem wynikającym z obcowania z cudem ludzkości, jakim była Wisła 64.

Spółka PolACME, w której zatrudniłem się jako inżynier, dostarczała rozwiązań obliczeniowych podmiotom w całym kraju oraz powoli zdobywała zagraniczne rynki. Naszym sztandarowym produktem był program Drzwi. Dedykowany był on na systemy oparte o Wisła 64 i stanowił wejście do wirtualnej przestrzeni operatorskiej, która umożliwiała wykonywanie wielu pomniejszych programów naraz oraz dostarczała szereg wygodnych narzędzi do zarządzania pamięcią operacyjną, jak i pamięcią pomocniczą. Wspierała zarówno taśmy magnetyczne, jak i magazyny talerzowe. Był to produkt tak świetny, że używali go nawet nasi inżynierowie i projektanci.
Dział, w którym pracowałem, opracowywał innowacyjne urządzenie rozszerzające do Wisła 64, które miało umożliwić bezpośrednią wymianę danych między dwiema maszynami na znaczne odległości. Roboczo zostało nazwane Piast, ponieważ miało połączyć maszyny kalkulujące, niczym pierwsi królowie Korony Polskiej połączyli nadwiślańskie plemiona.
Pierwsze prezentacje okazały się nie lada sukcesem. Kierownictwo zaczęło naciskać, żeby możliwe było podłączenie wielu takich urządzeń do jednej maszyny Wisła 64, dzięki czemu mogłaby się ona komunikować w wiele stron naraz. Ponadto dodano wymaganie, aby komunikacja działała również w trybie pośrednika(coś jak zabawa w "podaj dalej"). Przekroczeniem Rubikonu była jednak decyzja na zaadaptowanie produktu pod zagraniczne maszyny liczące. Podjęta ona została, ponieważ dyrekcja nawiązała współpracę biznesową z Dortmundzką spółką NWRW(Nordhein-Westfallen Rechenwerke GmbH) i podpisała kontrakt na ich autorską technologię o nazwie WindRad. Reklamowana była jako rewolucja w dziedzinie programowania obliczeniowego, ponieważ miała umożliwić uniwersalny zapis programu, który będzie możliwy do translacji na dowolny system obliczeniowy. Z założenia miało to odciążyć od projektowania programu na bazie konkretnej maszyny matematycznej, której niuanse wymagały podejmowania wielu decyzji dotyczących mało istotnych szczegółów.
Symbolika marki opisywała to jako podmuch wiatru na młyn napędzający inżynierię superwydajnych systemów obliczeniowego przetwarzania danych. My jednak zrobiliśmy sobie z niej obiekt żartów o tym, że wyraża ona podświadomą tęsknotę zarządu NWRW za reżimowym ustrojem, który ich naród sam obalił pokolenie wcześniej.

PolACME utworzyło specjalny dział, który miał pomóc NWRW w opracowaniu translatorów WindRad na maszyny Wisła 64 oraz Orzeł 8. Już po kilku miesiącach otrzymaliśmy prototypy, na bazie których mieliśmy opracowywać WindRadową wersję programu urządzenia komunikacyjnego Piast.
Czuć było w tym pewną inercję. Dokumentacja techniczna WindRada była opasła i poruszanie się po niej wymagało nieco wprawy. Pobieżne zapamiętanie spisu treści nieco przyspieszało ten proces. Sama treść dokumentacji dawała po sobie znać, że została przetłumaczona przez kogoś, kto średnio rozumiał język polski.

Wszystkie słowa kluczowe WindRada pochodziły z niemieckiego. Nie miałem z tym większego problemu, mój ojciec był z pochodzenia Niemcem. Ożenił się jednak z Polką i z tego powodu w Polsce się osiedlił. Pracował jako pianista w regionalnej filharmonii. Przekonywał często matkę, że nadał mi imię na cześć Chopina, jednak pod jej nieobecność opowiadał mi o chwale Cesarstwa Pruskiego oraz wielkości Świętego Cesarstwa Rzymskiego za panowania Barbarossy. Nie omieszkał przy tym wtrącać różne szlacheckie aforyzmy. "Pamiętaj synu, najpotężniejsza armia nie uczyni z ciebie władcy, jeżeli kupisz ją za cenę suwerenności."
Nie trafiało to wtedy do mnie, bo byliśmy prostą rodziną z miasta. Najpotężniejszym żołnierzem naszego domu była matka uzbrojona w tłuczek do kotletów. I bez tego była w stanie zrobić sobie z ojca podnóżek. Do końca życia nawijał o Czystości i tym, że liczy się tylko pismo i każdy ma takie same prawo jego interpretacji. Od czasu do czasu przebąkiwał coś o rzymskich uzurpatorach, którzy są diabłami świecącymi w ciemnościach. Jednak dla ukochanej Gracji ugiął się i ochrzcił jedynego syna po katolicku. Może to właśnie ta rozdwojona wizja na moje życie zaszczepiła we mnie jakiś dualizm, który uniemożliwił poważne podejście do obu z rodzimych wyznań. Poza tym nie potrafił wytrzymać choćby jednego przyjęcia bez tyrady o tym, jaki to ród von Nischwitzów nie był wpływowy, mimo że nie utrwalił się szczególnie na kartach historii. Wobec czego był prześmiewczo nazywany za plecami baronem Terenzem.
Ja również nie podzielałem tej sympatii, więc irytowało mnie gdy koledzy z pracy przychodzili do mnie z pytaniami o wpływ niuansów języka niemieckiego na WindRad, bo nie znałem go wcale aż tak dobrze.

Notacja, którą zapewnił nam WindRad od czasu do czasu pokrywała się ze schematami powtarzających się przypadków projektu Piast. Te schematy dokumentowaliśmy w formie biblioteki zawierającej schematy list instrukcji, które były opisane pod kątem problemu, jaki rozwiązywały. Notacja WindRada przypominała nieco notatki boczne tych dokumentów z tym, że nie były one tylko pustymi słowami, bo translator weryfikował spójność programu pod kątem użytych notacji. Niestety po przepisaniu bazowej części komunikacyjnej Piasta do WindRad maksymalna przepustowość danych spadła o niemal 30 procent. Wzbudziło to alarm u kierownictwa działu, bo kampania marketingowa zaczęła już obiecywać pewne liczby, a teraz okazały się one nieosiągalne.
Dlatego PolACME wystąpiło z podaniem do NWRW, aby zapewnili nam szkolenie w kwestii efektywniejszego używania WindRada. Producent WindRada zebrał wywiad od spółek używających ich produktu i spisał opasłe kompendium pełne różnorodnych technik i zasad użycia. Kopia woluminów trafiła do naszego działu i kierownictwo wymagało od nas ich studiowania i stosowania się do ich przykazu. Zorganizowanie sobie na to czasu oraz systemu współdzielenia dostępu do ksiąg pozostało kwestią przemilczaną. Napięcie wzrosło jeszcze bardziej, gdy dział rozwijający Drzwi zaczął adaptować konkurencyjną technologię. Ich kierownictwo zdecydowało się na wschodnie rozwiązanie o nazwie Szczipcy(ros. щипцы). Reklamowana była jako coś co pozwoli złapać rozgrzaną do bieli ideę programu i kuć ją póki gorąca. Poza tym miało się to kojarzyć z pewnym i bezpiecznym chwytem.
W rzeczywistości koledzy, którzy zaczęli je używać byli głównie uszczypliwi wobec wszystkich dookoła. Zaczęli nam suszyć głowy, że rozwiązania, które piszemy pod WindRad są podatne na awarie i manipulacje z zewnątrz, więc przezwaliśmy ich kultem czerwonego kraba.

Kuriozum osiągnęło punkt krytyczny w momencie, w którym doszło do sprzeczki między mną, a kolegą z działu o to jaki zapis w WindRadzie użyć. Popchnęło mnie to do przeprowadzenia iście szaleńczego badania, którym chciałem wykazać swoją rację, a w konsekwencji doprowadziło do niebagatelnych wniosków.
Przedstawię to za pomocą zapisów moich kontemplacji, które ukażą je z perspektywy bliższej temu, co myślałem i czułem w ciągu wydarzeń.

CAPUT II
DŻIHAD USPRAWIEDLIWIA ISKRĘ, OD KTÓREJ ŚWIAT STAJE W OGNIU

Pracuję nad realizacją protokołu ustanawiania łączności między dwoma modułami Piast. Zgodnie z wytycznymi każda próba ma odłożyć w dzienniku zdarzeń komunikat adekwatny do odpowiedzi otrzymanej z drugiej strony.
W dokumentacji projektowej, którą otrzymałem mam wylistowane jaki komunikat powinien trafić do dziennika w odpowiedzi na dany kod zwrotny.
Tak się składa, że widziałem już dosyć podobne przypadki w projekcie Piast i zazwyczaj były one realizowane za pomocą struktury sterującej FLIPPER. Dopiero niedawno dotarło do mnie, czemu została ona nazwana jak bilard elektryczny. Dopasowanie pod wartość obok słowa kluczowego REIN powoduje wykonanie instrukcji nawet jeżeli rozdzielają je inne REIN-y. Wiersz RAUS jest jak przeszkoda, która kieruje kulkę przepływu sterowania w bok.

DATEN kod ZAHL

FLIPPER kod
REIN 0
    TUN wpiszDoDziennika("abc")
    RAUS
REIN 1
    TUN wpiszDoDziennika("def")
    RAUS
REPPILF

Przypadki użycia FLIPPER-a z którymi się spotykałem bywały nieeleganckie. Bardzo raziły mnie zapisy w których kilkanaście REIN ów stanowi etykietę skoku dla tej samej operacji przypisania wartości do symbolu zmiennej lub wypisania komunikatu.

Przeglądając dokumentację WindRad szybko wpadłem, że da się to w bardzo prosty sposób wyrazić za pomocą agregującego typu danych ZIPP. Mogę potraktować kody zwrotne jako klucze i komunikaty jako sparowane wartości. Więc konkretny typ muszę zbudować z typów podstawowych ZAHL oraz KETTE.

DATEN komunikatySynchronizacji ZIPP[ZAHL->KETTE]
ANFANG
0 -> "abc"
ENDE

DATEN komunikatDziennika KETTE
komunikatDziennika := komunikatySynchronizacji[kod]

Wyszedłem z tą propozycją rozwiązania do reszty działu i otrzymałem komentarz od Michała, aby nie używać ZIPP-a. Twierdzi on, że jego działanie będzie zbyt wolne ze względu na dodatkowe alokacje pamięci za pośrednictwem systemu. Jak na ironię zasugerował, aby napisać to z użyciem FLIPPER-a.
Po paru wymianach argumentów w kwestii estetyki obu rozwiązań uznałem, że bardziej korzystnym dla projektu będzie zaakceptowanie jego sugestii niż twarda obrona swojego stanowiska, która skutkowałaby przeciąganiem pracy. Poza tym muszę mu nieco oddać honoru, bo jednak jest starszy stanowiskiem.
Przystałem na opakowanie FLIPPERA w podprogram. Dzięki czemu operacje związane z każdym REIN-em nie polegały na przypisywaniu wartości do symbolu komunikatu i wychodzeniu ze struktury sterowania słowem kluczowym RAUS, tylko zwracaniu wartości z podprogramu. Ta wartość może zostać przypisana do symbolu komunikatu przez wywołanie tego podprogramu.

UNTERPROGRAMM KETTE dopasujKomunikatDoKoduZwrotnego
kodZwrotny ZAHL
STARTE
    FLIPPER kodZwrotny
       REIN 0 ZUR := "abc"
       REIN 2 ZUR := "def"
    REPPILF
ENDE

DATEN komunikat KETTE
TUN dopasujKomunikatDoKoduZwrotnego(kod) =: komunikat

***

Mija kilka dni odkąd skończyłem prace nad wątkiem ustanawiania łączności. Temat dopasowywania komunikatu do kodu zwrotnego nadal nie jest w stanie ujść z mojej głowy.
Nawet początkujący programista powinien być w stanie z miejsca zapisać do niego rozwiązanie. Chociaż początkujący pewnie nie zreflektowałby się nad innymi możliwościami, a da się to zrobić na kilka sposobów o podobnym poziomie elaboracji.
Jakoś nie daje mi spokoju, że brakuje nam konsensusu co do tego, który sposób jest najlepszy. Wydawało mi się, że mam już dostatecznie dużo doświadczenia, żeby podejść do tego tematu bezbłędnie, a mimo to starszy kolega okazał się być za rozwiązaniem, które sam wcześniej w uzasadniony sposób odrzuciłem.
Problem jest tak prosty, że dyskusja wokół niego wydaje się być stratą czasu. Skoro problem jest trywialny, to czemu WindRad nie dostarcza czegoś, co rozwiązuje problem w sposób co do którego eksperci byliby zgodni?
Czyżby nie dotarła jeszcze do mnie jakaś tajemnica przez którą mój osąd jest gorszy? Może jestem jeszcze za mało obeznany z dokumentacją techniczną i wolumenami WindRada.

Zajrzałem do wolumenów w sekcje dotyczące FLIPPER oraz ZIPP. Księgi zalecają użycie FLIPPER postulując, że jest przetłumaczalny na tablicę skoków o szybkim czasie dostępu. Z kolei ostrzega, że ZIPP ma nieco długie czasy dostępu ze względu na rozsianie po pamięci operacyjnej. Czyli to uzasadnienie odrzucenia ZIPP nie było wzięte z powietrza. Nie dziwię się, bo Michał nie ma tendencji do obrzucania nas banialukami.
Z tym, że te zapisy w księgach nie zestawiają bezpośrednio obu notacji twarzą w twarz. Wobec czego w mojej głowie rodzi się pytanie względem czego są one szybkie lub wolne? Moim być albo nie być jest wprowadzenie nieco sceptycyzmu. Nie tak dużo, żebyśmy zaczęli kwestionować kulistość Ziemi, ale na tyle dużo, żeby zadać sobie pytanie "Skąd pewność, że dane rozwiązanie w WindRad będzie lepsze od innego?".
Przecież mamy narzędzia, które pozwolą nam zebrać dane na ten temat, a metoda naukowa pomoże nam znaleźć odpowiedź. Nie powinienem tak po prostu pozwalać na to, żeby ucierały się u nas schematy, które oparte są na przypuszczeniach. Być może za pierwszym razem schemat doboru poprzez FLIPPER został utworzony po najmniejszej linii oporu, za drugim razem skopiowany z pierwszego, a przy trzecim razie był już złotym wzorcem, którego złamanie stanowi podstawę do bicia na alarm.
Nie wiem jeszcze przeciwko komu albo czemu walczę. Czy jest to walka z kolegą o to kto ma rację czy może walka przeciwko kolektywnej głupocie ludzi z mojego zawodu? Walka z jednym nieprzemyślanym przypadkiem czy wręcz całym WindRadem, którego wprowadzenie wydaje się wnosić większe problemy niż te, które mieliśmy dotychczas? W każdym razie jest to walka warta podjęcia, bez względu na to jakie reperkusje mogą na mnie spaść.

CAPUT III
STATYSTYCZNIE ISTOTNY POMIAR WŁASNEGO CIENIA

Przed rozpoczęciem pomiarów dodam inne możliwe rozwiązania problemu, żeby nie przypominało to pojedynku z fantasmagorii typu Mozart kontra Bach.
Pierwszym co przychodzi mi do głowy jest struktura WENN. Podobnie jak FLIPPER jest to struktura wyboru.
W tym przypadku jednak każdy warunek będzie polegał na jawnym porównaniu symbolu kodu zwrotnego do wartości całkowitoliczbowej. Sprawdzenie reszty kodów zwrotnych mogę zawrzeć w łańcuchu DOCH WENN.
Struktura WENN ma tę zaletę, że nie wymaga jawnego wyskakiwania z bloków operacji dla spełnionego warunku tak, jak robi to RAUS we FLIPPER-ach. Jest to całkiem logiczne, jeżeli o każdym DOCH WENN pomyśleć jako o WENN-ie w sekwencji po DOCH.

DATEN kodZwrotny ZAHL
DATEN komunikatDziennika KETTE
WENN kodZwrotny = 0
    komunikatDziennika := "abc"
DOCH WENN kodZwrotny = 2
    komunikatDziennika := "def"
NNEW

Kolejnym, nieco mniej oczywistym rozwiązaniem będzie FOLGE. Jako, że kod zwrotny jest wartością całkowitoliczbową mogę użyć go jako indeks dolny ciągu i podobnie jak w ZIPP zawrzeć odpowiadające im wartości komunikatów.

DATEN komunikatyDziennika_10 FOLGE_KETTE
ANFANG
"abc"
"def"
ENDE

DATEN komunikat KETTE
DATEN kodZwrotny ZAHL
kodZwrotny := 1
komunikat := komunikatyDziennika_kodZwrotny

***

Uzyskałem dostęp po godzinach do stanowiska Wisła 64 działającego pod kontrolą systemu Drzwi. Przygotowałem program pomiarowy. Polega on na pomiarze czasu dopasowania elementu dla wejścia o wartości 0. Dla każdej wersji dopasowanie jest wykonywane 1000 razy, więc wynik dzielony jest przez tę wartość w celu uzyskania średniego czasu.

Wynik pierwszych pomiarów dla wersji z ZIPP jest niemal rząd wielkości większy niż pozostałe. Różnice pomiędzy pozostałymi są marginalne, ale FLIPPER wydaje się mieć minimalną przewagę.

Dodałem próbę kontrolną, żeby zobaczyć ile czasu zajmują same operacje związane z metoda pomiarową. Iteracja oraz przepisywanie wartości między symbolami również mają wkład w czas wykonania. Wygląda na to, że względem wersji innych niż ZIPP czas wykonania próby kontrolnej wynosi nieco ponad 50%.
Tym razem wersja oparta na ciągu miała najkrótszy średni czas wykonania. Liczyłem na to, że uśrednianie anuluje wzajemnie jakiekolwiek fluktuacje czasów pojedynczego wykonania. Spróbuję zmierzyć czas pojedynczego dopasowania.

Nie jest wesoło, 99% pomiarów to 0 albo 100 mikrosekund. Za to około jeden na sto pomiarów osiąga jakieś niebotyczne wartości typu 1 albo 10 milisekund.
Domyślam się, że to jakieś ograniczenia kwantyzacji zegara. Dziwne, bo opis podprogramu ZEIT w dokumentacji technicznej WindRad nie wspomina o niczym takim. Może to ograniczenie wynika z samej Wisły?
Bardziej niepokoją mnie jednak te pomiary odstające. Najpewniej system Drzwi jest w stanie wywłaszczyć wykonanie od programu, który aktualnie wykonuje się w jego środowisku. Trochę to dziwne, bo nie pomyślałbym, że może się to stać nawet przy tak małej skali operacji. Pewnie jakaś czarna magia Szczipców, cholerny kult czerwonego kraba! A może to jednak jakieś zachowanie Wisły nad którym wcześniej nie miałem okazji się pochylić?

Próbowałem przez chwilę estymować wartości pomiędzy kwantyzacją zakładając, że podlegają one stałemu rozkładowi dwuwartościowemu. Trochę jak szacowanie długości kijka poprzez rzucanie go na linie rozłożone równo w odległościach większych niż sam kijek. Ciekawe co powiedziałby na to Mistrz Ulam?
Wyniki nie są równe pomiędzy eksperymentami. Podejrzewam, że sam podprogram ZEIT nie dostarcza stabilnej wartości. Jakby nie było, nie może on mieć zerowego czasu wykonania i wartość, którą zwraca, będzie miała różną fazę względem pulsu zegara.
Że też podjąłem się tak zawiłego pomiaru. Chociaż to nie pierwszy raz, bo już kilka razy w pracy słyszałem dowcipy typu "Daj to Niszwicowi. On prędzej zrobi dziurę głową w ścianie, niż ośmieli się stwierdzić, że coś jest niemożliwe, zanim tego nie spróbuje.".

Wróciłem do pomiarów obejmujących wielokrotną operację dopasowania. Zacząłem od dobrania sensownej liczby operacji w ramach pomiaru czasowego. Zakładając, że kwantyzacja i błędy podprogramu ZEIT mogą wnieść +- 200 mikrosekund błędu do pomiaru to 2000 krotna operacja powinna przełożyć się na +-100 nanosekund błędu w średnim wyniku.
Tym razem nie liczyłem średniej tylko zebrałem serię 1000 pomiarów dla każdej wersji i przeanalizowałem.
Niestety pomiary nie wykazują żadnego pewnego rozkładu. Dla każdej z serii widać jakąś modę a nawet kilka, ale zawsze ciągnie się za nimi jakiś ogonek pojedynczych bardzo dużych wartości.

Udało mi się zniwelować duże wartości. Posortowałem serię i znalazłem w niej punkt za którym wartości rosną w znacznie szybszym tempie. Odrzuciłem wszystkie wartości za tym punktem i otrzymałem oczyszczoną serię w której mody stanowią środek wartości.
Jednak wciąż nie układają się w nic wyglądającego sensownie oraz replikowalnego pomiędzy eksperymentami. Myślałem, że na mocy centralnego twierdzenia granicznego osiągnę już zbieżność średniej.

Poeksperymentowałem nieco z liczbą wykonań operacji wewnątrz pomiaru. Dopiero teraz zdałem sobie sprawę, że błędy wynikające z wywłaszczania wykonania jedynie się akumulują, bo jest to opóźnienie, które nie może przyjąć wartości ujemnych. Zatem zwiększanie liczby operacji będzie jedynie zwiększać błąd.
Dlatego też nie jestem w stanie dokonać pomiaru, który doprowadzi mnie do wartości czasu wykonania samej operacji dopasowania. Zresztą nie ma w tym większego sensu, bo każde wykonanie jest obarczone ryzykiem opóźnienia. Więc wynik, który oddaje średnią wartość tego opóźnienia, również niesie nieco wartościowej informacji.

Dostroiłem liczbę operacji w pomiarze i rozmiary serii, dla których po usunięciu pomiarów z obu zagięć dystrybuanty otrzymałem rozkłady normalne, których parametry powtarzają się pomiędzy eksperymentami w tolerowalnych granicach.
Wygląda na to, że wersja oparta na FLIPPER daje najmniejszą wartość oczekiwaną, wersja WENN jest nieco wyższa, ale uwzględniając odchylenie standardowe nakładają się w ok 40%, co oznacza, że ta dominacja nie jest pewna. Z kolei wersja oparta na FOLGE jakkolwiek ma wartość oczekiwaną jedynie 10% większą, to nakłada się w obszarze dalszym niż 3 sigmy, więc jest praktycznie pewne iż będzie powolniejsza. Wartość oczekiwana przy wersji ZIPP pozostaje ok 8 razy większa niż pozostałe trzy.
Nie jestem w stanie wyciągnąć z tego żadnych pewnych wniosków dla pojedynczego dopasowania. Dosłownie powinienem powiedzieć, że wersja FLIPPER jest najszybsza w akumulacji czasu 2000 wykonań. Aczkolwiek koniec końców to i tak są tylko hipotetyczne wnioski z niezbyt formalnych eksperymentów. Nie wiem do końca jak udowodnić, że te wyniki rzeczywiście wynikają z doboru wersji zapisu. Być może wciąż główną rolę gra tu losowość.
Cóż za bezsens, tyle czasu i dni spędzone na eksperymentach, które nie udowodniły, że kolega miał rację, ale też nie wykazały wprost, żebym to ja się mylił. Wszystko rozbiło się o precyzje pomiaru, losowość i niepewności.
Chyba jedyna pewna mądrość jaką mogę z tego wyciągnąć, to że nie można powiedzieć nic pewnego na temat czasu wykonania jakiejkolwiek operacji dostarczanej przez WindRad. To jest taki miks charakterystyk samej operacji oraz systemu obliczeniowego na którym jest wykonywana, z którego praktycznie nie da się odseparować co od czego zależy. Gdybym wykonał te eksperymenty na Orzeł 8 to być może porządek czasów względem wersji byłby całkowicie inny. Dotychczas wydawało mi się, że dostrajanie programu w oparciu o takie wyniki jest wyższym poziomem jego okiełznania, a jednak okazuje się to być tańczeniem do rytmu, który zagra konkretna maszyna kalkulująca.

Z ciekawości sprawdziłem jeszcze jak operacje dopasowania mają się do samej operacji wpisu do dziennika. I okazało się to rewelacją, ponieważ średni czas serii operacji zapisu jest ok. 1000 razy większy niż czas operacji dopasowania.
To właściwie całkowicie zmienia punkt widzenia. Zamiast skupiać się na dyskusji o to, która wersja dopasowania komunikatu do kodu zwrotnego jest szybsza powinienem był przesunąć ją w stronę kwestii wpływu tego wyboru na szerszy kontekst programu. Przecież to samo wpisanie do dziennika jest głównym źródłem kosztów czasu wykonania.
Jaki jest sens, żebyśmy sami fatygowali się w oszczędzaniu grosików skoro wytyczne zmuszają nas do trwonienia złotówek? Źdźbło, które złamie wielbłądzi grzbiet padnie na kufry pełne kilogramów operacji, których dodanie do programu było zlecone z góry. Nikt nie pytał nas o zdanie jak wielkie są to koszty w porównaniu do wartości jaką dodają do produktu.

Więc w swoim zdaniu Michał się nie mylił, ale użył złego argumentu. Zapis ZIPP jest powolniejszy, ale z perspektywy użytkownika końcowego najpewniej nie byłoby to odczuwalne.
W takim razie to ja popełniłem błąd, bo dałem się wciągnąć w wartościowanie swojego rozwiązania wyłącznie pod kątem czasu wykonania jaki wprowadza.
Dlatego chcąc osądzić, które z nich jest lepsze, więcej zyskam, jeżeli przeanalizuję te zapisy w sposób całkowicie oderwany od jakiegokolwiek kontekstu w jakim mogą zostać osadzone.

CAPUT IV
ANALIZA UKŁADU ZAMKNIĘTEGO Z
PERSPEKTYWY WIĘŹNIA

Przeanalizuję użyte notacje WindRada w sposób całkowicie oderwany zarówno od systemów obliczeniowych na które mogą zostać przetłumaczone, jak i problemów względem których mogą zostać użyte.

Zaczynając od nieszczęsnego FLIPPER-a, który jest kością niezgody między mną a Michałem i może wręcz resztą działu.
Jako, że jest to struktura sterująca, to nie da się jej wprost zamknąć w żadnym symbolu. Można co najwyżej opakować ją w podprogram tak, jak zostało uczynione w ramach kompromisu. Zatem jej reużywalność wymaga dodatkowych notacji, ewentualnie skopiowania. To, czy skopiowanie jest dobre czy złe, zależy od tego, czy taka kopia reprezentuje coś niezależnego. Jeżeli nie, to będzie się miało do czynienia z powielaniem definicji, których zmiany będą wymagały synchronizacji w wielu miejscach.
Możliwe wartości wejściowe ograniczają się do liczb całkowitych. Także struktura nadaje się do użycia tak długo, jak wejście przyjmuje postać liczby całkowitej. Wyjątkowo FLIPPER ma jeszcze tę zaletę, że nie pozwala na zdublowanie wartości przy REIN-ie. Możliwość grupowania wielu takich REIN-ów uważam za wadę, bo widywałem już przypadki użycia w których takie zgrupowanie potrafiło liczyć kilkanaście wartości co wymaga sporego skakania oczami podczas czytania. Jednak jak wyszło w praniu, reszta zespołu nie podziela tego poczucia moralnego.
Możliwość umiejscowienia dowolnej sekwencji instrukcji pod etykietami daje swobodę strukturyzacji. Wykorzystuje się tego potencjał w przypadkach, kiedy działania są zróżnicowane dla każdego wejścia. Jedyne co nie daje mi spokoju to nieszczęsne RAUS. Dokumentacja techniczna nie tłumaczy się z tego, dlaczego wejście w jakikolwiek REIN będzie wykonywać wszystkie instrukcje poniżej, nawet rozdzielone innymi REIN-ami. Zgaduję, że pozwala to na opracowanie piramidy wartości wejściowych, wedle której bazowe wartości skutkują wykonaniem wszystkich instrukcji, z kolei każda kolejna grupa jest ich zawężeniem. Niestety nie spotkałem się w praktyce z takim użyciem, więc może taka potrzeba jest tylko wymysłem projektantów WindRada.

O strukturze WENN można powiedzieć dokładnie to samo w kwestii reużywalności oraz elastyczności struktury wewnętrznej. Przede wszystkim WENN daje swobodę warunków wejściowych, bo nie ogranicza się to tylko do porównania do konkretnej wartości całkowitoliczbowej. Z mojej strony plus za to, że sekwencje instrukcji do wykonania muszą być odseparowane. Większość przypadków użycia FLIPPER-a jest podatna na błąd ze strony programisty w postaci pominięcia RAUS, co skutkuje innym programem niż zamierzano. Z kolei WENN pozwala na błąd w postaci zdublowania warunku wejściowego, który nigdy nie zostanie przetworzony. Nie widzę jednak przeszkód, żeby program tłumaczący był w stanie zwrócić na to uwagę. No może poza zwiększonym czasem przetwarzania.
Ostatni DOCH pozwala na zagregowanie pozostałych przypadków. Można to wykorzystać do zdefiniowania działania w przypadku wejścia w stan nieokreślony.

Jakkolwiek uznałem ZIPP za najlepsze rozwiązanie dla przypadku dopasowania, to nie jest ono bez wad. Zamknięcie w symbolu daje reużywalność, a inicjalizacja par klucz-wartość jest zwięzła i czytelna.
Jednak w samej inicjalizacji jest pewien szkopuł, a mianowicie podobnie jak WENN nic nie stoi na przeszkodzie, aby w sekwencji wartości ten sam klucz pojawił się po raz kolejny. Podobnie jak z warunkami WENN zdublowany klucz nie przekłada się na żaden efekt, ponieważ wartość przy nim nie nadpisuje wcześniejszej.
Poza tym ZIPP nie umożliwia zdefiniowania reakcji na nieokreślony klucz. W przypadku próby uzyskania wartości dla nieokreślonego klucza zwrócona zostaje zeropodobna wartość typu wyjściowego. W przypadku KETTE jest to pusty łańcuch znaków. Dlatego też rozpoznanie takiej sytuacji wymaga dodatkowych instrukcji warunkowych w programie.

Typ danych FOLGE nieco przypomina nieślubne dziecko ZIPP-a oraz FLIPPER-a. Jednocześnie jest reużywalny pod postacią symbolu, ale ogranicza wartości wejściowe do liczb całkowitych.
Inicjalizacja również ma swoją podatność na błędy. Od programisty wymaga się zliczania już określonych wartości wyjściowych w celu określenia jakiej wartości wejściowej odpowiadają. Poza tym inicjalizacja wymaga przejścia wszystkich wartości pomiędzy, więc jakiekolwiek luki w wartościach wejścia będą wymagać uzupełnienia czymś oznaczającym wejście nieokreślone.
Najbardziej nieszczęsny jest w tym Grauzone związany z odgórnym określeniem liczby elementów. Odniesienie się do indeksu dolnego poza rozmiarem skutkuje nie wiadomo czym. Może to być katastrofa, a może to być jedno wielkie nic.

Pojęcie "moralności" jakim posłużyłem się w tym kontekście to tylko indywidualne poczucie estetyki oraz subiektywna ocena kroków pisania programu w których najłatwiej jest o pomyłkę i napisanie czegoś niezgodnego z intencjami. Nie ma w tym nic jednoznacznie rozdzielającego dobro od zła. Jak również nic obiektywnie wzbudzającego zachwyt albo obrzydzenie.
Jakkolwiek starałbym się przeanalizować te notacje WindRada w sposób całkowicie oderwany zarówno od konkretnego systemu, jak i od problemu, to nie jestem w stanie powiedzieć nic konkluzywnego bez umieszczania tego chociażby w kontekście konkretnego problemu, który rozwiązuję. Ba, bez poszerzenia tego kontekstu na całość projektu ten osąd również jest miałki. Problem jest prosty, ale trywialny może stać się dopiero wraz z ustaleniem pełnego kontekstu w którym jest osadzony. Tylko, że projekty same w sobie nie są czymś stałym, bo ich wymagania mogą ulegać ciągłej zmianie. Tylko ktoś kto zna projekt na wskroś oraz jego przyszłość jest w stanie dokonać optymalnego wyboru.

Chociażby wątek danych wejściowych: jakkolwiek ustalone zostało, że kody zwrotne przyjmą postać liczb całkowitych to nie można w pełni wykluczyć przyszłości w której zastąpione zostają one chociażby mnemonikami tekstowymi. W takim przypadku zapisy z użyciem FLIPPER oraz FOLGE przestają być bezpośrednio realizowalne. Ich wcześniejsze użycie wydaje się być założeniem ze strony programisty, że taka sytuacja jest wielce nieprawdopodobna.

Można również wyobrazić sobie sytuację w której zaistnieje potrzeba wyniesienia definicji komunikatów poza program, do danych konfiguracyjnych ładowanych w czasie jego wykonania z pamięci pomocniczej. W takim przypadku struktury sterujące tj. FLIPPER i WENN uniemożliwiają wprowadzenie zmian bez zdekonstruowania zapisu programu.

Wybór między strukturami sterującymi, a zawarciem dopasowań w symbolach również podlega pewnej spekulacji. Otóż zgodnie z wytycznymi każde otrzymanie kodu zwrotnego powinno skutkować wpisem komunikatu do dziennika. Co w momencie w którym dla pewnego kodu zwrotnego pojawi się specjalna wytyczna? Wtedy to struktury sterujące umożliwią najprostsze wprowadzenie jej do programu. Użycie ZIPP albo FOLGE wymagałoby chociażby ustanowienia osobnego bloku warunkowego.
Jednak użycie struktur sterujących dla kogoś innego może wydawać się nieco sugerować, że programista nie jest w stanie dostrzec ogólnego zachowania dla każdego przypadku, które polega na ustaleniu wartości komunikatu dziennika. Struktura WENN jest w tej kwestii jeszcze gorsza, bo dla każdego przypadku wejściowego powtarza operację porównywania kodu zwrotnego.

Z jednej strony widzę, że notacje WindRada mają w sobie pewien ukryty język projektowy. Nadają strukturę, która między słowami niesie różne intencje autora. Jednak z drugiej strony można ich używać jako pierwszy lepszy środek do celu. Nie przejmować się formą i stawiać na treść, która skutkuje oczekiwanym zachowaniem.
Jeden programista może kierować się maksymą, żeby robić coś raz, a dobrze i projektować swoje rozwiązania mając na uwadze możliwy krok naprzód. Drugi z kolei, że wystarczy rozwiązywać problem, który jest tu i teraz, a nie jakiekolwiek możliwe przyszłe problemy.
Obie postawy są pewnym wyborem, którego w zapisie programu praktycznie nikt jawnie nie oddaje. One nawet nie stanowią fundamentalnych pryncypiów, bo ta sama osoba może używać ich naprzemiennie w zależności od sytuacji i nastroju.
Temat prowadzi do czegoś przypominającego płot Chestertona, kiedy mając do czynienia z cudzym rozwiązaniem lub czymś, co zapisało się w dalekiej przeszłości trzeba się zastanowić, czy ustanowiona struktura i wynikające z niej ograniczenia mają znaczenie, czy są przypadkowe.

Łopatologiczny zapis sprawia wrażenie bycia dziełem łopatologicznie myślącego umysłu. W związku z czym używanie mniej wyrafinowanych środków wyrazu może okazać się strzałem w stopę, jeżeli ktoś wybiera je wyłącznie dla efektywności i chce tym sprawić wrażenie geniuszu. Poza tym czemu niby jedna składnia miałaby być w każdym przypadku lepsza od drugiej składni? Takie porównania bez kontekstu to jak rozstrzyganie wyższości między jabłkiem, a pomarańczą. Można kierować się konwencjami na temat parowania smaków, ale wybitny szef kuchni potrafi je łamać tak, jak wybitny muzyk potrafi wplatać dysharmoniczne interwały w melodię.
Jakby nie było to korekta błędu, a nawet całkowita zmiana notacji części programu i tak jest drobnostką w skali takich problemów jak to dopasowywanie komunikatów do kodów zwrotnych i inne, które mieszczą się w raptem parunastu linijkach tekstu obejmowalnych wzrokiem.
O wiele większym problemem może być zdiagnozowanie błędu jeżeli przeszedł on już wszystkie etapy procesu produkcji. Jego konsekwencje mogą przyjąć praktycznie wszystkie wartości w skali od niezauważalnych do śmierci ludzkiej i zależy to przede wszystkim od tego, do czego program jest używany.
Stara mądrość mówi, że ryba psuje się od głowy, zatem to w gestii kierownictwa projektu powinno leżeć ustanowienie kontroli jakości oraz barier linii technologicznej, które mają zapobiec wszelkim incydentom prowadzącym do odszkodowań. Zwracanie uwagi, że wydajność i odporność programu należy zapewniać działaniami oddolnymi programistów trąci propagandą, której celem jest spychalstwo odpowiedzialności odgórnej.

Po raz kolejny nie jestem w stanie dojść do porozumienia we własnym dialogu wewnętrznym względem rzekomo prostego problemu. Wobec czego zastanawiam się w jaki sposób NWRW udało się zebrać tyle porad i technik dotyczących WindRada samego w sobie? Czyżby tamci eksperci posiadali jakiś żelazny zbiór osobistych pryncypiów o których dotychczas nie słyszałem, a może po prostu nie posiadają zdolności refleksji i tarzają się w uprzedzeniach? Być może wręcz wpatrują się oni tak długo w coś, czego nie da się racjonalnie ocenić, że zaczynają prawić cokolwiek na bazie halucynacji wynikających z braku stymulacji mózgowej.
Po wdrożeniu WindRada co chwilę pojawia się jakiś głos, że nawet jak rozwiązanie elementarnego problemu jest poprawne pod kątem oczekiwanego efektu, to jest złe, bo jest zapisane nieładnie albo twierdzi się, że w danej notacji będzie wykonywać się zbyt powoli lub w sposób podatny na awarie. Co i rusz jest przerzucanie się zapisami "lepszymi" lub cytowaniami z ksiąg WindRada, że tak się robić nie powinno.
Nie pamiętam, żeby w czasach w których programowaliśmy bezpośrednio pod model Wisły 64 taka niezgoda w ogóle miała miejsce. Niemal każde rozwiązanie było dla nas zadowalające, a jeśli już zwracaliśmy sobie na coś uwagę, to na operacje nadmiarowe.
Przestało mieć pierwszorzędne znaczenie, żeby wykazać, iż program w danym zapisie będzie dostarczał oczekiwany efekt. Teraz głównie patrzy się na to, czy jest on zgodny z etykietą, a obejść to można jedynie sprytną retoryką lub nieczystymi zagrywkami.
Może uda mi się nieco zrozumieć to, co zaobserwowałem przy pomiarach jak zbadam to, od czego odepchnął mnie WindRad, a mianowicie program z perspektywy Wisły 64. Te rozmyślania oderwane od świata zewnętrznego sprawiają, że powoli sam zaczynam odchodzić od zmysłów.

CAPUT V
ZWIEDZANIE RAJU UTRACONEGO

Tak się składa, że program tłumaczący WindRad umożliwia przetworzenie do poziomu notacji pomocniczej Wisła 64, która umożliwia zapis programu w postaci mnemoników instrukcji.
Nieco czasu minęło odkąd ostatni raz pisałem program w tej notacji, więc muszę odgrzebać jakąś dokumentację użytkownika. Mam nadzieję, że analiza instrukcji Wisły do jakich tłumaczony jest WindRad rozjaśni nieco wyniki otrzymane w ramach pomiarów oraz doprowadzi do nieco bardziej konkluzywnych wniosków w kwestii sporu o to jak najlepiej napisać dopasowywanie komunikatu do kodu zwrotnego.
Żeby nie utrudniać sobie życia nieco zmienię badany program i zamiast dopasowywać wartość tekstową typu KETTE będę dopasowywał wartość liczbową z przecinkiem, czyli KOMMA. Wartości tekstowe z pewnością wymagają skomplikowanego kodowania oraz alokacji w pamięci, więc mogłyby nieco przyciemnić istotniejsze operacje.

Zaczynam od struktury danych ZIPP. Przygotowałem fragment definiujący grupę dwóch par oraz pobranie wartości dla klucza o wartości 8.

DATEN testowyZipp ZIPP[ZAHL->KOMMA]
ANFANG
5 -> 0,0625
8 -> 0,125
ENDE
DATEN wynik KOMMA
wynik := testowyZipp[8]

Oto instrukcje Wisła 64 jakie wyliczył program tłumaczący.

dod S #2
wst S@0 P#h12
dod S #1
wst R @Drzwi-DrzewoBinarne
rezerwuj
czyn
ode S #1
prze R @AUX1
wst S@-2 @AUX1
prze S @AUX1
wst R @AUX1
ode R #2
prze R @AUX1
wst S@0 @AUX1
wst S@2 #5
wst S@4 #h203f
dod S #6
wst R @Drzwi-DrzewoBinarne-wstaw
czyn
ode S #6
prze S @AUX1
wst R @AUX1
ode R #2
prze R @AUX1
wst S@0 @AUX1
wst S@2 #8
wst S@4 #h0023
dod S #6
wst R @Drzwi-DrzewoBinarne-wstaw
czyn
ode S #6
dod S #2
prze S @AUX1
wst R @AUX1
ode R #4
wst S@0 @AUX1
wst S@2 #8
dod S #4
wst R @Drzwi-DrzewoBinarne-znajdz
czyn
ode S #4
prze R @AUX1
wst S@-2 @AUX1
ode S #4

Pierwsze co rzuciło mi się w oczy to wywołania procedur zaczynających się od słowa Drzwi. A zatem translacja WindRad nie opiera się jedynie na możliwościach Wisła 64, ale wprost wspiera się funkcjonalnościami dostarczanymi przez program nadzorujący Drzwi. Właściwie to przypomniałem sobie, że materiały marketingowe dla programistów mówią o 64 niezbędnych funkcjach, które Drzwi dostarczają na Wisła 64.
Druga kwestia to fraza DrzewoBinarne: w dokumentacji ZIPP jest wzmianka o tym, że operacja dostępu do wartości ma złożoność logarytmiczną. W domniemaniu chodzi o logarytm o podstawie dwa, jak to zwykle bywa w obliczeniach opierających się na systemie binarnym. Domyślam się, że jako klucz może zostać użyty tylko typ posiadający określony porządek wartości, pewnie dlatego WindRad specyfikuje wymóg istnienia porządku leksykalnego znaków dla typu KETTE.
Z kolei WindRad nie dokumentuje nic na temat tego w jaki sposób taki ZIPP miałby być zakodowany w pamięci. Wartość zwracana przez procedurę "rezerwuj" jest umieszczana na stosie w dwuoktetowym bloku, który wygląda jakby był zaalokowany w odpowiedzi na samą deklarację ZIPP. Poza tym ta wartość jest przekazywana jako pierwszy argument do procedur "wstaw" i "znajdź". Zatem zgaduję, że zawartość drzewa jest przechowywana gdzieś w pamięci współdzielonej, zarządzanej przez Drzwi. Czyli w jakiś pośredni sposób Michał miał rację, że alokacja tego typu danych będzie skomplikowana. W takim razie pozostałe wersje pewnie nie korzystają z takich cyrków, bo tylko ZIPP miał średnio rząd wielkości dłuższy czas wykonania w tekstach.
Wróciłem do programu testującego i posprawdzałem nieco wpływ liczby par na czas wykonania. Wygląda na to, że więcej wartości w zbiorze przekłada się na zauważalny wzrost czasu dostępu i to nawet dla tego samego klucza. Ma to sens, ponieważ w drzewie binarnym umiejscowienie wartości jest zależne od wszystkich pozostałych. Wobec czego dodawanie kolejnych węzłów do drzewa skutkuje jego reorganizacją, i istniejący klucz może znaleźć się dalej od korzenia.

Dokonałem tego samego działania dla zapisu FOLGE.

DATEN folgeTestowe_3 FOLGE_KOMMA
ANFANG
0,0625
0,125
ENDE
DATEN wejscie ZAHL
wejscie := 1
DATEN wynik KOMMA
wynik := folgeTestowe_wejscie

dod S #8
wst R #0
@FOLGE1-INICJALIZACJA
prze R @AUX1
mn R #2
prze R @AUX2
prze S @AUX3
wst R @AUX3
ode R #8
dod R @AUX2
wst R@0 #h0020
wst R @AUX1
dod R #1
por R #3
wst R #rel@FOLGE1-INICJALIZACJA
sgm
wst S@-8 #h203f
wst S@-6 #h0023
dod S #2
wst S@-2 #1
dod S #2
prze S@-4 @AUX1
wst R @AUX1
mn R #2
prze R @AUX1
prze S @AUX2
wst R @AUX2
ode R #12
dod R @AUX1
prze R@0 @AUX1
wst S@-2 @AUX1
ode S #12

Pierwsza rzecz jaka rzuca mi się w oczy to alokacja 8 oktetów związana z deklaracją symbolu folgeTestowe_3. Wiem już, że symbol KOMMA potrzebuje 2 oktetów pamięci w których koduje bezpośrednio wartość, zatem oczekiwałbym alokacji 6 oktetów.
Poza tym nie pomyślałem dotychczas, że wszystkie elementy FOLGE inicjalizują się wartością zerową, ale z tego co widzę dokumentacja WindRad specyfikuje to wprost. Inna sprawa, że liczenie bazowego adresu ciągu powtarza się w pętli inicjalizacyjnej. Powinienem zgłosić to do działu rozwijającego program tłumaczący jako potencjał na poprawkę.
Kolejna ciekawa kwestia to sama operacja dostępu. Nie podlega ona żadnym skokom zapętlającym, co oznacza, że liczba rozkazów wykonywanych przez Wisła 64 jest taka sama dla każdego indeksu. Zatem domniemywam, że czas dostępu do dowolnego elementu jest taki sam bez względu na rozmiar i indeks ciągu. Sprawa byłaby zgoła inna, gdyby Wisła 64 nie dostarczała operacji mnożenia w modelu rozkazów. Wtedy mnożenie opierałoby się na wielokrotnym dodawaniu, co skutkowałoby złożonością liniową operacji dostępu.
Przeprowadziłem kilka krótkich pomiarów z różnymi indeksami i rozmiarami ciągu. Wygląda na to, że moja hipoteza o stałym czasie dostępu się trzyma, bo różnice w pomiarach wyglądają na przypadkowe.
Przeanalizowałem również translację do Wisła 64 po zmianie folgeTestowe na 5 elementów. W tym przypadku pierwszy rozkaz alokuje 16 oktetów na stosie, a nie 10, czyli tyle ile pamięci zajmują same dane. Więc wygląda na to, że translator dokonuje przydziału pamięci podzielnego przez 8 oktetów dla każdego FOLGE. To całkiem ciekawe z perspektywy wskazania indeksu poza rozmiarem jako przypadku Grauzone. W przypadku 5 elementów zapisanie czegoś pod elementem o indeksie 6 nadpisze pamięć, która nie jest używana przez żaden inny symbol, więc działanie programu nie powinno zostać zaburzone.
Mogę wykorzystać to odkrycie do utarcia nosa kolegom z działów używających Szczipiec, którzy twierdzą, że WindRadowe FOLGE to źródło wszelkich awarii i nadużyć programów. Szczególnie, że system Drzwi umieszcza zakodowane instrukcje programu w adresach poprzedzających stos wykonania. Biorąc pod uwagę, że dane kolejnych symboli WindRad mają rosnące adresowanie oraz konwersję wartości symbolu indeksu do wartości dodatniej, nadpisanie instrukcji własnego programu poprzez nadpisanie elementu FOLGE powinno być praktycznie niemożliwe.

Kolej na analizę zapisu opartego o FLIPPER.

DATEN wejscie ZAHL
wejscie := 0
DATEN wyjscie KOMMA
FLIPPER wejscie
REIN 0
    wyjscie := 0,0625
    RAUS
REIN 1
    wyjscie := 0,125
    RAUS
REIN 2
    wyjscie := 0,250
    RAUS
REIN 3
    wyjscie := 0,75
REPPILF

Z tego co widzę dopasowanie do konkretnego wejścia jest zrealizowane całkiem zmyślnie. Porównania do poszczególnych wartości wydają się być uporządkowane malejąco według samych wartości, a nie według kolejności REIN-ów wewnątrz FLIPPER-a. Skoki gdy mniejsze to najpewniej próba ominięcia całej struktury, gdy wejście jest większe niż jakakolwiek niesprawdzona jeszcze z określonych wartości. Jedynie wartości zero oraz jeden wyłamują się z tego schematu. Ciekaw jestem translacji przy innej kombinacji REIN-ów.

dod S #2
wst S@-2 #0
dod S #2
prze S@-4 @AUX1
wst R #3
por R @AUX1
wst R #rel@FLIP1-POR1
sgn
wst R #rel @FLIP1-REIN3
sk
@FLIP1-POR1
wst R #3
por R @AUX1
wst R #rel@FLIP1-KONIEC
sgm
wst R #2
por R @AUX1
wst R #rel@FLIP1-POR2
sgn
wst R #rel@FLIP1-REIN2
sk
@FLIP1-POR2
wst R #2
por R @AUX1
wst R #rel@FLIP1-KONIEC
sgm
wst R #0
por R @AUX1
wst R #rel@FLIP1-POR3
sgn
wst R #rel@FLIP1-REIN0
sk
@FLIP1-POR3
wst R #1
por R @AUX1
wst R #rel@FLIP1-KONIEC
sgn
wst R #rel@FLIP-REIN1
sk
@FLIP-REIN0
wst S@-2 #h203f
wst R #rel@FLIP-KONIEC
sk
@FLIP-REIN1
wst S@-2 #h0023
wst R #rel@FLIP-KONIEC
sk
@FLIP-REIN2
wst S@-2 #h0022
wst R #rel@FLIP-KONIEC
sk
@FLIP-REIN3
wst S@-2 #0h403f
nic
nic
nic
nic
@FLIP-KONIEC
ode S #4

Te bezwarunkowe skoki po niemal każdym przypisaniu wartości to musi być bezpośrednie przełożenie instrukcji RAUS. Widać to chociażby po REIN dla wartości 3, który w tym miejscu ma 4 instrukcje bezczynności. Wygląda jak gdyby program tłumaczący i tak i tak wstawiał 4 oktety do kodu, ponieważ skok pod wskazany adres jest kodowany w 4 oktetach, a instrukcja bezczynności tylko w jednym.
Może to jakieś wstępne przygotowania programu tłumaczącego do Wisła 64 na wdrożenie tabeli skoków? W tym konkretnym przypadku byłoby to jak najbardziej możliwe, bo wartości wszystkich REIN-ów są uporządkowane rosnąco, różnią się o 1, a instrukcje pod nimi kodują w tej samej liczbie oktetów. Z jakiegoś powodu jednak tak się nie dzieje. Może dział opracowujący program tłumaczący jeszcze doszlifowuje to rozwiązanie, a może jednak nie jest tej możliwości do końca świadomy, a wstawianie "nic" w przypadku braku RAUS wynika z innych konwencji?
Inna drobna kwestia, którą dopiero co zauważyłem jest taka, że jakkolwiek adres wierzchu stosu jest zwiększany w odpowiedzi na zadeklarowanie symbolu "wyjscie", tak nie przechowuje się w jego miejscu żadna wartość. Wyjaśnia to dokumentacja WindRada, która mówi, że proste symbole jak ZAHL oraz KOMMA mają niezdefiniowaną wartość po deklaracji. Wobec czego ich użycie przed przypisaniem wartości jest kolejnym przypadkiem Grauzone. W przypadku tego FLIPPER-a widać potencjał na awarię, bo wartość wejścia niedopasowana do żadnego REIN-u spowoduje, że do symbolu "wyjscie" nie trafi żadna wartość. To nieco dziwna decyzja projektowa mając na uwadze, że takie FOLGE na start określa wartość zeropodobną dla każdego elementu.

Została już tylko struktura warunkowa.

DATEN wejscie ZAHL
wejscie := 0
DATEN wyjscie KOMMA
WENN wejscie = 0
    wyjscie := 0,0625
DOCH WENN wejscie = 1
    wyjscie := 0,125
DOCH WENN wejscie = 2
    wyjscie := 0,250
NNEW

dod S #2
wst S@-2 #0
dod S #2
por S@-4 #0
wst R #rel@WYB1-ALT
sgn
wst S@-2 #h203f
wst R #rel@WYB3-KONIEC
sk
@WYB1-ALT
por S@-4 #1
wst R #rel@WYB2-ALT
sgn
wst S@-2 #h0023
wst R #rel@WYB3-KONIEC
sk
@WYB2-ALT
por S@-4 #2
wst R #rel@WYB3-KONIEC
sgn
wst S@-2 #h0022
@WYB3-KONIEC
ode S #4

Tym razem nic bardziej zaskakującego nie rzuca mi się w oczy. Porównania mają kolejność taką samą jak w zapisie WindRadowym. Jedyne co zwraca moją uwagę to bezwarunkowe skoki za koniec trzeciego WENN-a. Przetwarzanie sekwencji DOCH WENN-ów musi nastąpić w ujęciu całościowym, żeby wskazać gdzie znajduje się adres kolejnego rozkazu, który nie jest w żaden sposób związany z daną strukturą warunkową.

Przeprowadziłem jeszcze kilka pomiarów FLIPPER i WENN pod kątem czasu wykonania dla różnych wartości wejściowych. Wygląda na to, że w przypadku FLIPPER czas wykonania jest wprost proporcjonalny do wartości wejściowej, z kolei dla WENN odwrotnie. To by tłumaczyło dlaczego w pierwotnych pomiarach FLIPPER osiągnął minimalną przewagę. Czas wykonania w którym dopasowanie następuje w ostatnim DOCH WENN jest praktycznie taki sam jak czas wykonania dopasowania do 0 we FLIPPER.
Tylko, że jest to całkowicie bez sensu względem rozkazów Wisła 64. Wynika z tego, że większa ilość porównań przekłada się na mniejszy czas wykonania. Dotychczas popularna technika zliczania rozkazów dla konkretnych wartości wejściowych jako estymata czasu wykonania przestaje się sprawdzać.
Wygląda to jak gdyby Wisła 64 wykonywała taki ciąg rozkazów po swojemu i czas wykonania zależał od czegoś co jest przed programistą Wisły ukryte. To by wyjaśniało dlaczego dokumentacja Wisły nie mówi nic na temat liczby cykli zegara dla każdego rozkazu modelu. Jeżeli dobrze pamiętam Orzeł 8 określał pewne widełki, które były używane do szacowania czasu wykonania.

Jakkolwiek udało mi się dowiedzieć co nieco to po raz trzeci rozbijam się o ścianę na której namalowany jest krajobraz, który dotychczas uznawałem za prawdziwy. Karmiony kłamstwem, że maszyna robi dokładnie to co się jej rozkaże myślałem, że można przewidzieć wszystko na temat jej działania dostateczną ilością eksperymentów i analizy wyników.
W związku z tym nie jestem w stanie odeprzeć wrażenia, że opracowywanie jakichkolwiek praw dotyczących przekładu instrukcji programu na czas wykonania ma w sobie jakąś ironię losu. Takie prawa mają na celu wygranie z czasem na etapie wykonania, ale nad nimi samymi wisi miecz czasu, który w dłuższej perspektywie może przekreślić ich prawdziwość. Zaiste, marność.

Zastanawia mnie w związku z tym w jaki sposób opracowano reguły zapisane w księgach WindRada? Dokumentacja techniczna WindRada nie odnosi się nigdzie wprost do aspektów, które opisują. To by znaczyło, że oparte są na obserwacjach dokonanych w ramach wykonania programu w konkretnym systemie, na konkretnej maszynie liczącej. Tylko co daje gwarancję, że inne maszyny będą działać tożsamo? Ten brak świadomości separacji między WindRadem, a jego realizacją na konkretną maszynę sprawia, że wiązanie zapisu programu ze skutkami jego wykonania ma w sobie znamiona myślenia magicznego. Wierzenia, że skoro wykonanie programu następuje po jego zapisaniu, to każda właściwość wykonania jest skutkiem tego, co zostało zapisane. Tylko, że pomiędzy tymi zjawiskami jest jeszcze sporo zmiennych czynników, których kontrolować się nie da, a mają one ogromny wpływ na efekt końcowy.
Teraz zdaję sobie sprawę, że autorzy treści do wolumenów WindRada moralizują nie mniej niż Eliza Orzeszkowa. Większość akapitów przypomina wielkiego, kaznodziejczego palucha, który wymachuje przed nosem szczekając "tak rób, a tak nie rób; to dobre, to złe". Obrazy o szybkości i bezpieczeństwie, które przy tym kreują są szyte podobnie grubymi nićmi jak historyjki o utopcach, południcach i innych bebokach, którymi zniechęcano średniowieczne dzieci do swawoli. Wręcz mam wrażenie, że konsumując te treści nie tyle staję się lepszym programistą, co sam jestem programowany.

Męczy mnie to niezmiernie, bo jakkolwiek nie czułbym, że to zjawisko obraża moją inteligencję to widzę w nim pewien pragmatyzm. Posługiwanie się metaforą tego co namacalne w zakłamanie prostym i intrygującym kształcie, do opisu konceptów niedostrzegalnych gołym okiem, pomaga zrozumieć je choćby i szczątkowo. Spojrzenie na rzeczywistość taką jaka jest w swojej pełni może być oślepiające i powodować uczucie, że jakiekolwiek poznanie jest niemożliwe.
Może przespanie się z tą myślą pozwoli mi nieco uporządkować to we własnej głowie?

CAPUT VI
SŁOŃ JAKI JEST KAŻDY WIDZI, WIĘC
UPAJAJMY SIĘ!

Cóż za numer wywinęła mi fortuna. Myślałem, że sen przyniesie mi spokój, gdy tymczasem jego mary popchnęły mnie na granicę manii.

Śniło mi się, że znajdowałem się w teatrze. Siedziałem na środku widowni, tuż pod sceną i poza mną nie było na niej nikogo. Na scenie znajdowało się pudło - wysokie i długie na ponad dwa metry.
Po chwili na scenę wyszedł mężczyzna ubrany we frak. Miał na sobie cylinder oraz jedwabną pelerynę. Otworzył pudło pokazując, że w środku jest całkowicie puste, następnie zamknął je z powrotem. Obszedł je dookoła wymawiając egzotyczne frazy i harmonijnie machając rękoma. W rytmie tej choreografii wydobyło się kilka kłębów dymu oraz iskry drobnych eksplozji. Zbieżność jego ruchów i efektów była lekko nie w fazie, po około dwóch minutach tej pretensjonalnej pantomimy otworzył pudło i moim oczom ukazał się słoń w całej okazałości. Zwierzę było piękne, pełne wdzięku i miało taką aurę, jakby wszystko w tym pomieszczeniu zależało od niego. Zrobiło to na mnie niemałe wrażenie, więc mimo wcześniejszego paździerza uhonorowałem estradowca oklaskami. Światła zgasły, po paru minutach zapaliły się ponownie, a scena była w stanie początkowym.
Na scenę wyszedł ten sam mężczyzna. Dokonał tego samego aktu, tym razem efekty były bogatsze i lepiej zsynchronizowane z jego gestami i inkantacjami. Poza tym trwało to odczuwalnie krócej. Znowu ukazał się słoń, tym razem pomalowany w białe wzory przypominające polinezyjskie tatuaże. Światła zgasły.
Kolejny pokaz, ten sam artysta, niemal ta sama choreografia. Kolejny słoń, ubrany w lazurową derkę oraz tiarę. Tym razem stało się coś co wprawiło mnie w osłupienie, ponieważ słoń oddał poród na środku sceny. Zza kulis wyszło dwóch tęgich mężczyzn i zabrało nowo narodzone słoniątko. Światła zgasły.
Jeszcze raz to samo, ale mistrz wyszedł na scenę w obecności znacznie młodszego mężczyzny w podobnym stroju. Tym razem wykonali choreografię synchroniczną, asystent nieco mniej zgrabnie, ale mistrz zdawał się nie zwracać na to większej uwagi, tylko trzymać swojej roli. Kolejny słoń, w innej dekoracji, nie byłem w stanie powiedzieć, czy to słonica z poprzedniego pokazu. Światła zgasły.
Powtórka spektaklu, znów wyszło dwoje eleganckich mężczyzn, tym razem nie było już pierwotnego artysty, tylko poprzedni asystent wydawał się tym razem występować w roli mistrza. Znów tańczyli synchronicznie, jednak nowy mistrz wydawał się być wyraźnie poirytowany ślamazarnością ucznia, bo co i rusz fukał w jego stronę. Ukazał się słoń i po raz drugi na scenie dokonał się akt narodzin. Obaj prezenterzy wydali się być tym bardziej zaskoczeni niż ja. Nikt nie wyszedł zza kulis, a kiedy słoniątko wstało na nogi i obróciło się w stronę nowego mistrza, ten czmychnął w stronę drzwi ewakuacyjnych, jego asystent stał jak wryty. Wtedy zza kurtyny wybiegło nieco podrośnięte słoniątko i zaszarżowało w stronę ucznia, on odwrócił się i również zaczął biec, ale było już za późno. Zwierzę dogoniło go i zadało mu cios w sam środek pleców. Chłopak padł na wznak, a pod nim rozlała się plama szkarłatu. W płucach zrobiło mi się chłodno i odrętwiale.
Powoli wstałem, bestia z zakrwawionym kłem zwróciła się w moją stronę i podeszła parę kroków bliżej. Popatrzałem jej prosto w oczy, a ona zatrzymała się metr od krawędzi estrady. Wydała z siebie parsk i pobiegła z powrotem za kurtynę, a za nią poczłapało nowo narodzone słoniątko. Usiadłem na miejsce, światła zgasły.

Po paru minutach, kiedy adrenalina ze mnie zeszła reflektory zapaliły się ponownie. Przestałem wierzyć moim oczom, bo na scenę wyszło słoniątko-morderca ubrane w cylinder i pelerynę. Przez parę minut nieudolnie imitowało ruchy artystów, ale dymy i huki w ogóle nie szły w parze z jego gestami. Ostatecznie nie było w stanie otworzyć pudła, więc z kwikiem zbiegło ze sceny.
Siedziałem tak przez chwilę, aż reflektory przygasły. Wstałem i podszedłem parę kroków, by wspiąć się na podest sceny. Doczołgałem się do budki suflera i włożyłem głowę do środka, żeby zajrzeć pod deski teatru.
W słabo oświetlonej piwnicy znajdował się wyciąg z platformą oraz panel sterowania. Przy panelu stało małe słoniątko i nieudolnie pociągało za dźwigienki oraz stukało w przyciski. Po dokładnym rozejrzeniu się zauważyłem, że w rogu leżą ciała tęgich mężczyzn oraz młodego artysty.
Uznałem, że najwyższa pora stąd uciekać. Wyjąłem głowę z budki i wstałem w stronę wyjścia. Zacząłem biec, ale podłoga pode mną przesuwała się w przeciwną stronę, więc nie byłem w stanie przemieścić się o krok. Nagle z pudła wydobył się wysoki głos, który mimo dudnienia brzmiał całkiem dystyngowanie. Przestałem biec.
-"Wybacz mi, moje dzieci miały wam ulżyć w trudach. Nie przewidziałam jednak, że dokonają tego w tak makabryczny sposób."
-"Dlaczego tylko mnie nie zabiły?" - Odpowiedziałem.
-"Bo nie okazałeś im strachu. Twoja wola twórcza jest silniejsza niż one. Tamci stali się martwi, ponieważ wraz ze zdjętym wysiłkiem wygasło momentum ich egzystencji. Utrapienia zajmowały w pełni ich serca, dlatego utracili je wraz z nimi."
-"Mogę im jeszcze jakoś pomóc?"
-"Czemu zakładasz, że jest im z tego powodu źle?"
-"Nic z tego nie rozumiem."
-"Bo wciąż jesteś bliżej początku drogi. Liczy się tylko to, żebyś rozpoznał mnie następnym razem."
-"Ale... nie wiem jak masz na imię."
-"Uśmiechniesz się do mnie jak do kogoś, kogo skrycie kochasz."
Światła zgasły.

Pamiętam tylko, że zerwałem się z łóżka, doskoczyłem do stolika i zacząłem skrobać notatkę. Po jej popełnieniu znowu zasnąłem, tym razem już zupełnie twardo. O poranku znalazłem ten zapisek, który wydaje się być wyjść z ręki innego człowieka.

Eureka! W swoich badaniach rozbijałem się o ściany ponieważ cały czas zadawałem pytania, na które nie da się odpowiedzieć w sposób obiektywny.
Chyba zapomniałem, że od początku zależało mi przede wszystkim na tym, żeby tworzyć.
W moje ręce włożono narzędzia, które nie tyle miały otworzyć mi możliwości kształtowania dzieła, co ustanowić ramy ograniczające ten proces.
Narzędzia oddalające od efektu końcowego tak bardzo, że cała sztuka wydaje się polegać na odpowiednim wymachiwaniu nimi przez artystę.
Sam zacząłem popadać w tę iluzję zaczynając zadawać pytania o to, które z moich ruchów skutkują najlepszej jakości detalami dzieła.
Gdy tymczasem rzeczywistość dookoła mnie stała się płynna i więcej zaczęło zależeć od jej kaprysów.
Uwierzyłem, że kreatywność można usystematyzować w zbiorze doskonałych wzorców użycia nieskazitelnego zestawu technik, a mistrzowski twórca ma je wszystkie wyryte w duchu i układa z nich kolaże.
Stałem się jednym z głupców, którym cały czas się wydaje, że mają panowanie co do szczegółu i każdy efekt przypisują własnym działaniom. Głupców, którzy z procesu twórczego robią ceremonię i ustalają jak wykonywać ją poprawnie. Przypisujących narzędziom twórczości oraz własnym decyzjom tajemne cechy oraz osobowość, które rzekomo tylko nieliczni mogą pojąć.
W pogoni za tym urojonym pięknem zapomniałem, że na samym początku zależało mi przede wszystkim na tym, żeby tworzyć, urzeczywistniać swoje intencje.
Moją pierwotną intencją nie było, żeby moje dzieła były idealne, ale przede wszystkim, żeby mogły zaistnieć.
Dopiero w odpowiedzi na krytykę zacząłem krzywo na nie patrzeć. Skoro są one dla kogoś niezadowalające, a ich składowe nie spełniają kryteriów, to znaczy, że moje ręce lub umysł czynią źle.
Radość sprawczości zaczęła ustępować rozpaczy z powodu braku uznania. Desperacko zacząłem się karmić wszystkim tym, co nie pozwalało sobie na cień wątpliwości. Wiedza przestała stanowić drogowskazy do celu, zamiast tego stała się etosem, a jej stosowanie elitystyczną etykietą.
Wpadłem w bańkę wyimaginowanej moralności oraz sztucznych kanonów piękna.
Dopiero wewnętrzne poczucie, że zaakceptowane reguły nie dostarczają obiecywanej wartości doprowadziło do pęknięcia. Chcąc pozostać wewnątrz mentalnie bezpiecznego miejsca musiałbym stłumić swój wewnętrzny ogień albo cierpieć tworząc w sposób sprzeczny z własnymi uczuciami.
Niezgoda międzyludzka oraz brak pokrycia rzeczywistości z ideałami pozwoliły mi dostrzec bezsens ustanawiania prawdy absolutnej. Znajdując się w krzyżowym ogniu sprzecznych informacji o tym co dobre, a co złe pozostało mi jedynie rzucić się w ramiona myśli, że nie działamy dla etyki samej w sobie, ale dla własnego szczęścia.
Prowadzi to do wyzwolenia, twórczości nieskrępowanej, nieuległej wobec kryteriów ani krytyków. Dzieł, które podlegają tylko wymaganiom stawianym przez samego autora, owoców czystej pasji oraz pragnienia sięgnięcia gwiazd.
Pozwala to stać się autorem, którego ograniczają tylko prawa wszechświata, osobiste granice poznania oraz reguły własnej gry. Kogoś kto wytwarza własne narzędzia ekspresji zrozumiałe tylko sobie i muzom, zabawki do manifestacji swojego geniuszu. Twórcy, który nie akceptuje żadnych narzuconych ram jako obiektywnej prawdy.
Każda zrodzona przez niego myśl jest jak czasza wina, każdy jego ruch materializujący ją jest jak kufel piwa. Upaja się on tym procesem i rośnie w siłę wraz z wysiłkiem.
Nie tworzy on po to, żeby przypodobać się bogom. Chce w ten sposób stać się im równym, a nawet ich przewyższyć. Swoimi dziełami wytknąć każdy ich błąd w dziele wszechświata i stworzyć dziedzictwo, które pozwoli mu godnie zająć ich miejsce.
I nawet w momencie w którym potknie się o własne nogi, bo okaże się, że zatruł się myślami opartymi na fałszywych fundamentach. Powstanie, bo wie, że to dzięki zajściu tak wysoko uświadomił sobie bzdurność swojego światopoglądu. Zburzy to co zbudował dotychczas i zacznie od podstaw. Wszystko po to, aby móc budować jeszcze wyżej.
I nawet w tym procesie pozostanie upojony wizją stworzenia dzieła, które będzie kochać ponad własne życie, a w euforii nie przestanie wołać.
Niech żyje sztuka!

Podejrzewam, że jakiś dowcipniś dosypał szałwii do mojego melanżu tytoniowo-ziołowego, którym raczę się wieczorami.

CAPUT VII
TRANSCENDENCJA NIEOSIĄGALNA

A może w tym napadzie szaleństwa kryje się jakiś głos rozsądku?
Może używanie WindRada sprawiło, że chodzę z klapkami na oczach i przestaję widzieć rzeczy w najprostszej możliwej formie, bo nie dopuszczam jej istnienia do swojej świadomości?
Przecież matematyka dostarcza mi sposobów wyrażenia problemu i jego rozwiązania w formie prawdziwie oderwanej od materii. Teoria zbiorów powinna mi wystarczyć do ich ustrukturyzowania.
Określone kody zwrotne to nic innego jak skończony podzbiór zbioru liczb całkowitych. Z kolei komunikaty również mogę wyrazić jako zbiór, tym razem będący podzbiorem czegoś co można określić jako zbiór tekstów. Taki tekst precyzyjniej można określić jako skończony ciąg znaków o niestałej długości. Znak może stanowić zarówno litera, cyfra, znak interpunkcyjny, przerwa między słowami. Dokładna definicja w tym kodowanie tekstów nie ma znaczenia dopóki rozważa się wyłącznie dopasowanie tekstu do kodu zwrotnego.

Nieco to uciążliwe do wyrażenia w notacji algebraicznej. Skoro używam każdej litery polskiego alfabetu jako elementu zbioru znaków, to używanie ich jako symboli wartości i funkcji nie powinno następować. Poza tym wszelkie znaki specjalne, które stanowią interpunkcję, a jednocześnie są używane w standardowej notacji matematycznej, również powinny przyjąć formę jakiegoś arbitralnie wybranego symbolu, który pozwoli je odróżnić. Jakby nie było WindRad też mierzy się z podobnym problemem, bo znak cytatu otwiera i zamyka wartość tekstową, więc nie może on wprost wystąpić w tekście, bo oznaczałby jego koniec.

Jako, że są to dwa zbiory i celem jest dopasowanie elementu drugiego pod określony element pierwszego to wszystkie dopasowania można zamknąć w postaci funkcji. Zbiór kodów zwrotnych stanowi jej dziedzinę, a zbiór komunikatów przeciwdziedzinę. Będzie ona suriekcją, ponieważ z natury problemu nie ma sensu określać w zbiorze komunikatów wartości, które nie stanowią wartości tej funkcji.

Zatem w ujęciu czysto matematycznym problem i jego rozwiązanie są już ustrukturyzowane. Jednak WindRad nie dostarcza żadnych gramatyk, które mówią wprost, że są odzwierciedleniem matematycznych zbiorów oraz funkcji.
Może to jakaś świadoma decyzja projektowa? Charakterystyczny dla zbioru jest brak narzuconego porządku jego elementów. Coś co umyka percepcji kiedy definiuje się zbiór poprzez ogólny wzór jego elementów albo wypisuje się je na tablicy w postaci graficznej. Chcąc nie chcąc każdy tekst przetwarzany przez kalkulator musi mieć określoną kolejność słów, więc elementom takiego zbioru trzeba by nadać jakiś porządek, choćby arbitralny. Druga kwestia jest taka, że funkcji po prostu nie stosuje się do elementów spoza jej dziedziny i jest to kwestia trzymania się praw matematyki, których złamanie prowadzi do błędnych wniosków. W przypadku obliczeń zautomatyzowanych kiedy przyszłoby do sytuacji, w której jako argument funkcji trafiłaby się wartość spoza dziedziny, maszyna musi mieć w swoim programie sposób rozpoznania takiej sytuacji oraz określony sposób reakcji na nią.
Poza tym jest jeszcze kwestia tego, jak ma działać dopasowanie elementu. Z ludzkiej perspektywy wskazanie wartości funkcji dla argumentu przy dziedzinie o mocy parunastu jest czymś tak intuicyjnym jak wskazanie konkretnego owocu na półmisku. Maszyna potrzebuje algorytmu do takiego działania.

Biorąc pod uwagę, że funkcje można zanotować w postaci tabelarycznej, mogę jawnie oznaczyć kolejność wierszy i potraktować ją jako kolejną wartość w modelu. Wtedy nie muszę wychodzić zbytnio poza teorię zbiorów, bo wystarczy, że zarówno zbiór kodów zwrotnych jak i komunikatów przyporządkuję do zbiorów n pierwszych liczb naturalnych o równej mocy. Dzięki czemu zdefiniuję skończony ciąg dla obu z nich. W tak zdefiniowanych ciągach kolejność elementów obu zbiorów podlega tożsamości dla dopasowanych kodów zwrotnych i komunikatów. Więc przyporządkowanie kodu zwrotnego do komunikatu mogę zdekomponować na funkcję ciągu komunikatów oraz odwrotność funkcji ciągu kodów zwrotnych.


Chcąc znaleźć komunikat pasujący do kodu zwrotnego mogę wykorzystać algorytm wyszukiwania liniowego w ciągu kodów zwrotnych i zapamiętać kolejność elementu ciągu na potrzeby jego użycia do wskazania elementu ciągu komunikatów.

Pozostaje kwestia nieokreślonego kodu zwrotnego. Jestem w stanie nie wychodzić poza myślenie funkcjami. Kody zwrotne są podzbiorem liczb całkowitych, więc mogę rozszerzyć dziedzinę na wszystkie liczby całkowite. Mogę utworzyć binarny zbiór reakcji: reakcję typowa i reakcję awaryjną. Reakcja typowa to przepisanie konkretnego komunikatu do jakiegoś symbolu wyjściowego. Za dopasowaniem wartość tego symbolu będzie stanowiła wejście dla operacji wypisywania tekstu. W ramach reakcji awaryjnej mogę powtórzyć komunikację albo przerwać program. Przy czym ciężko powiedzieć czym matematycznie są te reakcje, bo mają one charakter samego programu obliczeniowego, więc ni to wartość, ni to funkcja. Definiując zbiór operacji na danych oraz reakcję jako krotkę tych operacji wróciłbym do punktu wyjścia, bo model matematyczny miał się oderwać od charakterystyki instrukcji. Najprościej będzie zatem potraktować te reakcje jako opis tego co się zadzieje w formie rachunku zdań.

Ostatecznie nie jestem w stanie sobie wyobrazić jak można by zapisać ten problem w taki sposób, żeby jednocześnie odcinał się od wszystkich niewygodnych decyzji, a mimo to był przetwarzalny maszynowo. Przede wszystkim tym niewygodnym szczegółem jest sposób dopasowania wejścia do wyjścia. Jakkolwiek przeszukiwanie liniowe jest najbardziej uniwersalnym sposobem, to przecież zdążyłem już zaobserwować, że dla wejścia o wartości naturalnej i wyjściu o stałym rozmiarze dopasowanie można przeprowadzić poprzez rozwiązanie równania liniowego. To jest diametralna różnica w złożoności, której nie mogę zignorować. Poza tym w przypadku przeszukiwania liniowego pożądane jest, żeby najbardziej prawdopodobne wejście znajdowało się na pierwszym miejscu ciągu określającego porządek.
Oprócz tego jest kwestia umożliwienia rozpoznania sytuacji niezdefiniowanego wejścia. Podejście do tego również jest zależne od rodzaju wejścia i wyjścia. Może ono opierać się na wartościach specjalnych, jak i skokach.
Powinienem wziąć jeszcze pod uwagę kwestię reużywalności i modyfikowalności. Przeprowadzenie dopasowania poza miejscem definicji jego wartości również stanowi pewną niedogodność w kwestii wykonywalności. Patrząc chociażby na to, że odległość operacji od danych jest wtedy zmienna. Modyfikowalność wydaje się być jeszcze większym problemem, ponieważ ilość pamięci potrzebna do przechowania definicji dopasowań może być wtedy możliwa do ustalenia dopiero na etapie wykonania, w miejscu w którym chce się dopasować wyjście do wejścia.
Dlatego opracowanie rozwiązania, które jest jednocześnie wygodne i sprytne w działaniu wydaje się być chęcią zjedzenia ciastka i zachowania go jednocześnie. Pewne kluczowe decyzje dotyczące sposobu wykonania obliczeń muszą zostać podjęte na etapie programowania, a ich skutki niemożliwe do przewidzenia bez ustalenia konkretnych cech kalkulatora.

Mimo porażki widzę, że matematyczny model komunikuje problem i rozwiązanie w bardzo czysty sposób. WindRadowe zapisy wydają się być przy nim płaskie. Może WindRad nie ma pierwszorzędnego celu dostarczać sposobów formowania myśli i ich przekazu? Jego składowe elementarne są znacznie bardziej intuicyjne w użyciu niż model Wisły 64, ale praktycznie wszystkie zanieczyszczone są pewnymi uprzedzeniami, które ujawniają, że WindRad przede wszystkim służy do sterowania maszyną. Nie faworyzuje on żadnej konkretnej maszyny, więc jej fizyczne cechy nie są określone. Jednak nie potrafi się też oderwać do takiego poziomu abstrakcji, żeby wszelkie algorytmiczne zagwozdki mogły zostać rozwikłane automatycznie.

CAPUT VIII
ENDOMORFIZACJA JAJKA KOLUMBA

Ten matematyczny model, który opracowałem wcale nie musi być czymś prawdziwym tylko na papierze. Trochę wysiłku sprawi, że wszystkie WindRadowe zapisy rozwiązań jakoś się w niego wpasują. Dzięki czemu jak na dłoni będzie widać, że każdy z nich nie jest czymś zupełnie innym, tylko zniuansowanym ukonkretnieniem jakiegoś matematycznego konceptu.
Przecież FOLGE to dosłownie ciąg, on zdaje się iść w tym na skróty i nie definiuje osobnego ciągu dla kodów zwrotnych i komunikatów, tylko łączy to w całość i przeplata zdefiniowane kody zwrotne z wartościami nieokreślonymi pomiędzy. Wszystko opiera się na tym, że dziedzina jest podzbiorem liczb naturalnych, więc funkcja określająca porządek zbioru kluczy jest tożsamościowa. Równoodległość elementów sprawia, że znalezienie dopasowania to kwestia podstawienia klucza jako argument dyskretnej funkcji liniowej.
Z kolei ZIPP wygląda na całkiem wierne oddanie ogółu funkcji dopasowania z tym, że przeciwdziedzina zawiera wartość bez dopasowania w postaci wartości zeropodobnej. Poza tym realizacja za pomocą wyszukiwania binarnego zamiast liniowego redukuje złożoność procesu dopasowania do logarytmicznej.
Trochę ciężej jest mi spojrzeć w ten sposób na zapisy oparte o struktury sterujące. One same w sobie są czymś innej natury niż zbiory i funkcje. Jednak jeśli wziąć pod uwagę schematyczność w warunkach oraz listach wewnętrznych operacji to są to jawne wyrażenia operacji niezbędnych. Porównanie do konkretnego kodu zwrotnego jest czymś co niejawnie należy dokonać zarówno w wyszukiwaniu liniowym jak i przeszukiwaniu drzewa binarnego. Listę operacji dla każdego kodu zwrotnego można potraktować w charakterze reakcji typowej. Wtedy nawet brak RAUS-ów w FLIPPER-ze będzie zgodny z ideą. Sam FLIPPER w swoich restrykcjach wartości REIN-ów i ich niepowtarzania dosyć dokładnie odzwierciedla charakter funkcji określającej porządek ciągu kodów zwrotnych.
Biorąc pow uwagę kwestie reakcji awaryjnej to najprościej odda ją struktura WENN, ponieważ ostatni DOCH może stanowić przypadek w który wpada się dla wszystkich nieokreślonych kodów. Taki FLIPPER nie posiada nic analogicznego, więc sprawdzenie musiałby nastąpić przed, ewentualnie po próbie dopasowania. Podobnie ma się wersja FOLGE, wpadnięcie w Grauzone sprawi, że przestanie ona sensownie pasować do modelu matematycznego. Można określić specjalną wartość dla wszystkich liczb pomiędzy do jakiegoś górnego zakresu i po dopasowaniu sprawdzić, czy wpadło się w przypadek awaryjny. W tej kwestii tożsamy jest zapis ZIPP z tym, że wartość zeropodobna stanowi odgórnie narzuconą wartość specjalną.

Zatem mając na uwadze abstrakcyjny model matematyczny powinienem być w stanie sformalizować reguły możliwości przekształcenia między zapisami oraz algorytmy dokonania tych przekształceń.
Chcąc przekształcić ZIPP we FLIPPER kluczem musiałaby być wartość całkowitoliczbowa, a w miejscu dopasowania wartości do klucza wszystkie kluczpary musiałyby być możliwe do ewaluacji z samego zapisu. Najprościej byłoby to osiągnąć dla ZIPP-a, który nie ulega zmianie po zdefiniowaniu.

%sd - symbol dopasowań
%Tw - typ wartości
%ki(%k1, %k2, ..., %kn) - i-ty klucz
%wi(%w1, %w2, ..., %wn) - i-ta wartość
%sw - symbol dopasowanej wartości
%we - bezpośrednia wartość lub symbol wejścia

DATEN %sd ZIPP[ZAHL -> %Tw] KONST
ANFANG
%k1 -> %w1
%k2 -> %w2
[...]
%kn -> %wn
ENDE
DATEN %sw %Tw
%sw := %sd[%we]

Struktura FLIPPER używałaby tej samej bezpośredniej wartości lub symbolu jako wejścia co operand dostępu ZIPP przy pobieraniu wartości dla wskazanego klucza.
Dla każdej pary klucz-wartość ZIPP-a, wewnątrz FLIPPERA utworzony zostałby REIN o wartości klucza oraz operacja przypisania do symbolu wyjściowego o wartości odpowiadającej kluczowi oraz następujący po tym RAUS.
Przed strukturą FLIPPER należy przypisać wartość zeropodobną do symbolu wejściowego jako odpowiednik działania ZIPP-a dla klucza nieokreślonego.

Mając zdefiniowane takie przekształcenia mógłbym opracować specjalne przypadki dla programu tłumaczącego w których translacja następuje do instrukcji Wisła 64 odzwierciedlających wydajniejszą strukturę WindRad. Klucze należałoby uporządkować malejąco, zatem dla przykładu można założyć, że spełniają następującą relację.
%k1 < %k2 < ... < %kn
Nie mogę zakładać, że przyporządkowanie wartości będzie działać w jednej instrukcji, więc muszę je traktować jako bliżej nieokreśloną sekwencję instrukcji.
Chcąc uogólnić na użycie symbolu i bezpośredniej wartości jako wejścia założę, że wartość wejścia jest już umieszczona pod adresem pomocniczym @AUX1.
Schemat dopasowania z użyciem ZIPP-a przekształcalnego na FLIPPER miałby następującą postać w instrukcjach Wisła 64.

dod S #%Tw-rozmiar
%przyporządkowanie-%Tw
zeropodobne-do-S@-%Tw-rozmiar%
wst R #%kn
por R @AUX1
wst R #rel@PORÓWNANIE-n
sgn
wst R
#rel@PRZYPORZADKOWANIE-Wn
sk
@PORÓWNANIE-n
wst R #%kn
por R @AUX1
wst R #rel@KONIEC
PRZYPORZADKOWAN
sgm
[...]
wst R #%k2
por R @AUX1
wst R #rel@PORÓWNANIE-2
sgn
wst R
#rel@PRZYPORZADKOWANIE-W2
sk
@PORÓWNANIE-2
wst R #%k2
por R @AUX1
wst R #rel@KONIEC
PRZYPORZADKOWAN
sgm
wst R #%k1
por R @AUX1
wst R #rel@PORÓWNANIE-1
sgn
wst R
#rel@PRZYPORZADKOWANIE-W1
sk
@PORÓWNANIE-1
wst R #%k1
por R @AUX1
sgm @KONIEC
PRZYPORZADKOWAN
@PRZYPORZADKOWANIE-W1
%przyporządkowanie-w1-do-S@-%Tw
rozmiar%
wst R #rel @KONIEC
PRZYPORZADKOWAN
sk
@PRZYPORZADKOWANIE-W2
%przyporządkowanie-w2-do-S@-%Tw
rozmiar%
wst R #rel@KONIEC
PRZYPORZADKOWAN
sk
[...]
@PRZYPORZADKOWANIE-Wn
%przyporządkowanie-wn-do-S@-%Tw
rozmiar%
@KONIEC-PRZYPORZADKOWAN
ode S #%Tw-rozmiar

W przypadku, gdy klucze stanowią kolejne wartości całkowitoliczbowe od 0 do n-1 możliwa byłaby translacja do pojedynczego skoku o wyliczonym adresie.
Istotną rolę będzie grało w tym ile oktetów zajmuje schemat przyporządkowania wartości do symbolu wyjściowego.

%prz - rozmiar instrukcji przyporządkowania typu Tw do zmiennej na wierzchu stosu

dod S #%Tw-rozmiar
%przyporządkowanie-%Tw-zeropodobne-do-S@-%Tw-rozmiar%
wst R @AUX1
mn R #%prz
sk
@PRZYPORZADKOWANIA
%przyporządkowanie-w1-do-S@-%Tw-rozmiar%
wst R #rel@KONIEC-PRZYPORZADKOWAN
sk
%przyporządkowanie-w2-do-S@-%Tw-rozmiar%
wst R #rel@KONIEC-PRZYPORZADKOWAN
sk
[...]
%przyporządkowanie-wn-do-S@-%Tw-rozmiar%
wst R #rel@KONIEC-PRZYPORZADKOWAN
sk
@KONIEC-PRZYPORZADKOWAN
ode S #%Tw-rozmiar

Jako, że modyfikowanie programu tłumaczącego jest poza moimi możliwościami, mogę wywinąć to rozwiązanie na lewą stronę i opracować poprzedzający krok translacji, który zamieni źródłowy zapis WindRad na zapis wtórny, który zostanie przekazany do właściwego programu tłumaczącego.
Zapis FLIPPER utworzony ze schematu ZIPP-a wyglądałby wtedy następująco.

DATEN %sw %Tw
%sw := %Tw%_NULL
FLIPPER %we
REIN %k1
    %sw := %w1
    RAUS
REIN %k2
    %sw := %w2
    RAUS
[...]
REIN %kn
    %sw := %wn
    RAUS
REPPILF

Zastanowiłem się nad tym dłużej i mam wrażenie, że zjadam własny ogon. Narzekałem na to ile skomplikowania wprowadza kompendium WindRada i jego regułki, a teraz sam wymyślam niestandardowe procesy do projektu, które tylko zwiększyłyby jego złożoność.
Potrzebuję jakiejś rewelacji, czegoś co pozwoli mi zrozumieć czemu programy obliczeniowe tworzymy tak, a nie inaczej. Co daje moc, a co stanowi kulę u nogi?

CAPUT IX
CZŁOWIEK CZŁOWIEKOWI
RZEMIEŚLNIKIEM RZECZYWISTOŚCI

Spędziłem tak dużo czasu nad czymś co stanowi tylko kroplę w morzu potrzeb projektu. Liczyłem, że uda mi się odnaleźć jakąś absolutną prawdę, a jedyne co znalazłem to więcej niepewności.
Może to nieprzypadkowe, nie wierzę, żeby był to jedyny problem dla którego nie da się opracować uniwersalnie doskonałego rozwiązania. Nie chcę ulegać iluzji, że pojawienie się jednej jaskółki oznacza wiosnę, ale mam nieodparte wrażenie, że te doświadczenia mają mi do przekazania coś na temat mojej pracy ogólnie. A może po prostu nie jestem w stanie pogodzić się z tym, że poświęciłem tyle energii na coś bezproduktywnego?
Dowiedziałem się, bo widziałem na własne oczy, ponadto nikt nie wpychał mi do głowy co mam o tym pomyśleć.
Czyż nie to stanowi o dojrzałej zdolności do działania, które przynosi soczysty owoc? Mógłbym się tego samego dowiedzieć przy herbacie od kogoś kto przetwarzaniem informacji i maszynami liczącymi parał się lata więcej ode mnie. Tylko w mówieniu o tym, że niemożliwe jest dokładne ujęcie prawdy jest pewien paradoks. Ironia zapisania, że nie należy wierzyć wszystkiemu co się czyta. To skomplikowanie rzeczywistości można poczuć tylko kiedy zrobi się coś zgodnie z wszystkimi uznawanymi ideałami i okaże się, że to wciąż za mało, żeby ująć problem w punkt.

Nie wiem, czemu wcześniej nie przyszło mi to dosłownie na myśl, ale przecież WindRad nie spadł z nieba. On został opracowany przez ludzi, którzy widzą i czują zupełnie tak samo jak ja. Ludzi o podobnym wykształceniu i aspiracjach jak my w projekcie Piast, ludzie z działu rozwijającego Drzwi oraz ludzie, którzy stworzyli Wisłę 64. Wszyscy pracujemy nad czymś co ma na celu zautomatyzować żmudne przetwarzanie danych i wykorzystuje do tego obliczenia. Coś co jest w stanie rozwiązać całą gamę problemów dzięki zmienności, ale ma również elementy stałe, dzięki którym nie jest bezpostaciowe.
Projekt Piast w tym stanie nie istniałby bez ludzi pracujących nad WindRadem, bez ludzi pracujących nad Drzwiami, bez ludzi pracujących nad Wisłą 64. Oni również mają swoje zaplecze technologiczne, które przedłuża ten łańcuch. Z pewnością są w nim jeszcze ludzie badający matematykę oraz zjawiska elektromagnetyczne.
Opracowując program Piasta stoję na barkach gigantów, którzy ukształtowali świat mojej pracy. Jakikolwiek osobisty sukces jest współudziałem ludzi, którzy zapewnili mi podstawy jego osiągnięcia.

W tym obrazie WindRad jawi się jako coś przypominającego umowę. Umowę, która wiąże programistów bliższym informacjom, które są przetwarzane, z programistami bliższymi maszynom kalkulującym.
Tych pierwszych można by określić jako konsumentów lub użytkowników, tych drugich jako producentów lub dostawców.
Użytkownikom obiecuje ona pewne efekty przetwarzania danych, a dla dostawców stanowi wymagania dotyczące obliczeń jakie musi dokonać maszyna.
Dlatego twórcy WindRada balansują między utworzeniem czegoś co da jak największą wygodę konsumentom i stanowić będzie jak najmniejszy problem w realizacji producentom. Elementarnych składników budulcowych, które można wyprowadzić z modelu praktycznie każdej maszyny.
Brak intuicyjnych narzędzi ekspresji zniechęci tych pierwszych, z kolei zobowiązanie dostarczenia złotych gór tych drugich.
Z perspektywy użytkownika można wręcz pomyśleć o tym jak o automatyzacji tworzenia dystrybucji na konkretną maszynę. Niewidzialna ręka wolnego rynku deleguje tę pracę do producenta WindRada.
Aczkolwiek zaadoptowanie WindRada w projekcie Piast sprawiło, że wszystko zaczęło kręcić się wokół niego. Konsekwencje decyzji twórców i producentów WindRada zaczęły na nas spływać na dobre i na złe. Przez co czasem miałem wrażenie zostania zamkniętym w złotej klatce.
Ta relacja uświadamia mi, że programowanie jest komponowaniem, a nie wirtuozerią. Liczy się dopieszczanie dzieła, a nie jak najlepsze wykonanie w jednym podejściu. Poza tym nie wymaga to budowania żadnej intymnej relacji z instrumentem. Zastanawia mnie zatem, czy możliwe jest analogiczne tworzenie na całą orkiestrę manipulacji danych, której różnorodność wydobywania informacji niczym dźwięku łączy się w harmonię?

Zastanawiam się jeszcze jak WindRad wpasowuje się w inne projekty i inne maszyny matematyczne. Z pewnością nie jesteśmy jedynym klientem NWRW.
Biznes i maszyny kalkulujące to jakby dwa lądy oddzielone rzeką, którą mało kto potrafi przekroczyć, więc życie po obu jej stronach rządzi się nieco innymi zasadami.
Potrzeba czegoś co ułatwi przemieszczanie się między tymi dwoma obszarami, a jednocześnie nie będzie zbyt obszerne w konstrukcji. Takim mostem jest właśnie WindRad.
Lustrując sam most nie da się zrozumieć tego co dzieje się po obu jego stronach. Poza tym nie kryją one w sobie nic ponad to, co zawarli w nich inżynierowie oraz budowniczy.
Możliwości, które wynikają z ich istnienia to iloczyn kartezjański z mnogością ludzi i pojazdów, która je przekracza. One są cudem techniki, ale ich studium ma wartość przede wszystkim dla ludzi, którzy sami chcą je stawiać.
Gdyby taki most stanął w miejscu w którym nie ma żadnych naturalnych barier, to stanowiłby jedynie zawężenie ruchu i spowolnienie jego przepływu. Wymuszenie korzystania z takiego mostu stanowiłoby zysk jedynie dla poborców myta.

To już około osiem miesięcy od momentu rozpoczęcia dostosowywania Piasta pod WindRad. Ciężko mi uwierzyć, że dopiero teraz uświadamiam sobie czym on jest. Byłbym w stanie to zrozumieć niedługo po tym, jak został on nam rzucony na biurka. Gdybym tylko od razu zadał sobie to pytanie zamiast nastawiać się na jak najszybsze osiągnięcie jakiegokolwiek efektu. Nie potrzeba mi już w jego temacie zgłębiać na zapas nic więcej.
Teraz dopiero rozumiem, że uczę się wtedy, kiedy obcuję z czymś co napełnia mnie zdumieniem. Każda inna konsumpcja informacji to tylko zapoznawanie się z kolejnymi sztucznymi tworami, które reprezentują znane mi koncepty. Nie muszę znać wyniku każdej przeprowadzonej dotychczas w historii operacji dodawania, żeby móc bez wstydu posługiwać się tytułem matematyka. Przecież jestem w stanie go wyprowadzić dla dowolnych rozsądnie wielkich liczb.
Zrozumiałbym wcześniej, gdybym nie tkwił w pułapce mentalności, że to narzędzia są kluczem do zrozumienia swojej pracy. A przecież one powinny stanowić jedynie przedłużenie własnego ciała i umysłu. Myśląc odwrotnie jestem tylko trybikiem machiny. Największym atutem wielkich pisarzy nie jest doskonała znajomość rodzimego języka, ale zrozumienie świata i zdolność zakomunikowania jego percepcji innym. Terminologia, gramatyka i interpunkcja mają jedynie chronić nas od nieporozumień i niejasności.
Może to jakaś niezdrowa kultura nieustannego zwiększania efektywności pracy spycha nas do tego dołka i zmusza do poszukiwania schematycznych technik? Tylko w programowaniu to nie ma zbyt wiele sensu, bo każdy pomniejszy problem, który jest optymalnie rozwiązany, można zapakować w coś reużywalnego, co jest reprodukowalne poprzez kopiowanie oktetów.
Marzy mi się dyscyplina, która zebrałaby pod jednym dachem wszystko co w maszynowym przetwarzaniu danych najbardziej przydatne. Selekcję teorii nauk z których to wykiełkowało oraz systemat technologiczny nieskażony marketingowym bełkotem.

To, co dokonałem w ramach moim badań, może stanowić metodę odpowiadania na każdy kolejny wymóg znalezienia optymalnego zapisu w WindRad. Wszystko, co niezbędne mi będzie jeszcze się dowiedzieć, jest w jego dokumentacji technicznej, którą mam pod ręką.
Aczkolwiek wątpię, że jestem w stanie skodyfikować tę metodę w taki sposób, żeby była użyteczna dla każdego. Moja edukacja i dotychczasowe doświadczenia z Wisłą 64 musiały mieć ogromny wpływ na to, czy byłbym w stanie znaleźć się w miejscu, w którym jestem właśnie teraz. Gdybym swoją przygodę z kalkulatorami zaczął od WindRada, to pewnie nie zdziałałbym za jego pośrednictwem więcej, niż byliby mnie w stanie pokierować inni jego użytkownicy. Jakkolwiek wiele możliwości nie wydawałby się otwierać. Może nawet rzeczy, które mówił do mnie ojciec o tym zadecydowały, chociaż wyrażał je w sposób, który przede wszystkim dla niego miał sens?
Gdybym tylko mógł cofnąć się w czasie i zapytać go o to. Jednostronność komunikacji nie tylko jest źródłem nieporozumień, ale wręcz ma potencjał do nadużyć. Sam przecież mógłbym wykorzystać przewagę wiedzy do zrobienia z siebie guru. Mógłbym zmanipulować swoich pupili do uwielbiania wszystkiego co jest mi bliskie i nienawidzenia wszystkiego co mi nie w smak. Stworzenia wyselekcjonowanego echa, które wpada w samoistny rezonans. Obiecywać, że utoruję im drogę do lepszego świata, w którym będą wiecznie nagradzani za samo recytowanie moich nauk. Świata w którym nie trzeba podejmować żadnego oryginalnego wysiłku. Propagować mentalność, że problematyka zawodowa jest jak dyskomfort różnych części ciała i dokonywać komodyfikacji kompetencji w ergonomiczne poduszki. Wystarczyłoby nigdy nie przyznawać się do błędu, każdą porażkę ogłaszać jako sukces.
O niebiosa, gdybym kiedyś stał się takim obłudnikiem, to przyślijcie na moją kolację posąg Commendatore, który ześle mnie wprost do Tartaru.

***

Sprzątając biurko znalazłem karteczkę na której były nabazgrane poniższe słowa.

Opinie ludzkie są jak dźwięki ptaków.
Bywają skrzekliwe, powtarzalne i irytujące.
Lecz gdyby ich nie było, las wydawałby się martwy.

Przeczytanie tego napełniło mnie jakąś niewytłumaczalną radością. Rozpoznałem charakter swojego pisma, ale nie byłem w stanie sobie przypomnieć, kiedy mogłem to napisać. Zupełnie jakby moją ręką kierował jakiś duch, który był ze mną całe życie, a jednocześnie przeżył mnie po tysiąckroć i istniał zanim powstało wszystko to, co mnie otacza.
Jak gdyby chciał mi w ten sposób przekazać, że nie ma nic nowego pod Słońcem. Każdy rynek i społeczność można przejąć nową modą, ale ono jako jedyne pozostaje Niezdobyte.
Dało mi to mieszankę uczuć ukojenia, ale jednocześnie nieco wstydu, że odczuwam coś niewyjaśnialnego wobec bytu, którego nie jestem w stanie nazwać, a nawet potwierdzić ani zaprzeczyć jego istnienia.
Wiem tylko tyle, że nie ma sensu obawiać o przyszłość, bo wszystko co dotychczas przeżyłem ma sens tak długo, jak będę czerpał z tego sensowne wnioski. Albowiem rzeczywistość i tak będzie ulegać zmianie, a ja razem z nią. Odejdę w niebyt dopiero wtedy, kiedy już zabraknie mi woli na stworzenie nowego siebie wyróżniającego się na jej tle, przez co scalę się z przedwieczną jednością.

CAPUT X
KAŻDY PUNKT DROGI
TO POCZĄTEK I KONIEC

Jeżeli czytasz ten rozdział bez zapoznania się z poprzednimi licząc, że to tu znajduje się mój przekaz, to pewnie wierzysz naiwnie, że wartość tkwi w znalezieniu się u celu podróży, a nie w niej samej. Jeszcze nie jest za późno na zepsucie sobie tego. Chyba, że zostało to poprzedzone sprawdzeniem co ludzie myślą.

Nieco lat minęło od czasu, kiedy wydarzyły się rzeczy opisane przeze mnie w przedstawionych notatkach. Pojawiły się maszyny liczące jeszcze bardziej zaawansowane niż Wisła 64, więc ślady po Wisłach łatwiej znaleźć na złomowiskach, niż w jakichkolwiek organizacjach przetwarzających dane.
Perypetie PolACME były wyboiste. Pierwszy cios, który na nas spadł był wstrząsem wtórnym, który wynikał z tragedii jaka dotknęła NWRW. Otóż wysłali oni w delegację zagraniczną cały dział WindRada i zdecydowali się na budżetowy czarter sterowcem. Tanie koszta usługi korelowały z tanimi kosztami przedsięwzięcia. Sterowiec został napełniony wodorem zamiast droższym wtedy helem. Późniejsze śledztwo wykazało, że awaria układu elektrycznego spowodowała zapłon, co skutkowało śmiercią wszystkich ludzi na pokładzie.
Zarówno NWRW jak i nasz dział wdrażający WindRad nie był w stanie podnieść projektu z kolan. NWRW zdecydowało się go pogrzebać, a nasza spółka zmuszona do ratowania czego tylko się da. Projekt Piast cofnął się o kilka lat w rozwoju i skomunikowanie Wisł z powrotem weszło w strefę marzeń niczym postawienie stopy człowieka poza Ziemią.
Mimo tego, że nigdy nie spotkaliśmy się twarzą w twarz, ludzie od WindRada pozostali w naszych sercach jako przyjaciele po fachu. To, co nam dostarczali, wytworzyło jakąś paraspołeczną relację bez względu na to, czy ich dzieło spełniało nasze oczekiwania czy nie. Ułożyliśmy na ich cześć melancholijną gitarową balladę, którą śpiewaliśmy przy integracyjnych ogniskach. Opowiadała ona o tym, jak to WindRad przewijał się razem z nami przez dobre czasu i złe czasy oraz jak nić komunikacji przerwała się przez ogień, który ją strawił. Samego WindRada nie było mi szkoda, bo nigdy nie uznawałem go za jakąś podstawę mojej osobowości zawodowej.
Projekt Szczipcy również nie miał lekko. Zawirowania polityczne u naszych wschodnich sąsiadów zmusiły do zrezygnowania z importu ichniejszej technologii.

W takich okolicznościach PolACME zdecydowała się na opracowanie własnych rozwiązań. Doświadczenia z zagranicznymi technologiami dostarczyły nam wystarczająco materiału do opracowania czegoś, co w pierwszej kolejności spełni nasze potrzeby. Nawiązana w związku z tym współpraca ludzi z projektu Piast oraz projektu Drzwi uświadomiła nam, że więcej było między nami wspólnego aniżeli różnic.
Projekt, który powstał w ramach tej współpracy, został nazwany Macierzą. Garściami czerpaliśmy zarówno z WindRada jak i Szczipców. Adaptowaliśmy wszystko to, co było dla nas w pełni zrozumiałe i wychodziło naprzeciw naszym oczekiwaniom. Projekt okazał się tak owocny, że PolACME postanowiło uczynić z niego źródło przychodu.
Długo i stanowczo negocjowaliśmy z dyrekcją temat marketingu Macierzy. Zależało nam na tym, żeby nie obiecywał on tego, czego w praktyce nie jesteśmy w stanie dostarczyć. Nasz ultraszczery marketing rozpoczynał się następującą preambułą.

Programowanie obliczeniowe stanowi jeden, nieokreślony w pełni byt.
Istnieje wiele sposobów na stworzenie kalkulatora. Ogół kalkulatorów spełniających zbiór ustalonych cech stanowi klasę kalkulatora.
Istnieje skończenie wiele sposobów na zaprogramowanie każdego kalkulatora. Abstrakcyjna notacja programistyczna stanowi bliżej nieokreślony byt będący rzutem programowania obliczeniowego na przestrzeń wyrażeń formalnych. Określa ona notację programów oraz klasę kalkulatorów na którą jest przetłumaczalna.
Macierz jest abstrakcyjną notacją programistyczną opracowaną na potrzeby projektu Drzwi oraz Piast, z pierwotnym wsparciem dla maszyn kalkulujących Wisła 64 oraz Orzeł 8.

Byliśmy bardzo dumni, że udało nam się ukonstytuować Macierz. Jednakże nie wzięliśmy pod uwagę prostej rzeczy, a mianowicie łaski opinii publicznej, która na pstrym koniu jeździ.
PolACME podpisała kontrakt na rządowy projekt opracowania systemu regulowania podatków. Projekt został iście wzniośle ochrzczony Abstrakcją i słuchy o nim dotarły do niemal każdego obywatela. Niestety w praktyce okazało się, że jest on niedopracowany od strony założeń projektowych i niezrozumiałym trafem zaczął podnosić podatki w taki sposób, że odbiło się to głównie na wzroście cen towarów pierwszej potrzeby. Niezadowolenie społeczne było tak duże, że rząd postanowił wycofać się z projektu i obarczyć konsekwencjami finansowymi PolACME. Mleko się rozlało, PolACME ogłosiło upadłość, a prawa autorskie jego projektów wpadły w administracyjny dołek. Samo słowo "abstrakcja" okryło się przez to taką hańbą, że z ekspozycji zaczęto zdejmować dzieła Pollocka. My, programiści osieroceni po PolACME, jakoś sobie z tym poradziliśmy podmieniając je iście swojskim "niekonkretnikiem". Kryzys ekonomiczny sprawił, że przez jakiś czas przestano podejmować się próby tworzenia programów na wiele różnych maszyn kalkulujących naraz.

Przytaczam te wydarzenia, ponieważ mam wrażenie, że historia zaczyna zataczać koło. Doszły mnie słuchy, że rynek zaczynają zdobywać nowe produkty, które w swoim opisie przypominają abstrakcyjne notacje programistyczne. Każdy z nich ma inne zdanie na temat tego co w programowaniu istotne a co trywialne.
Jednak tym razem nad nimi wszystkimi majaczy jeszcze widmo panaceum, które obiecuje łatwiejsze opanowanie dowolnej z takich technologii poprzez kolejny poziom automatyzacji. Jestem sceptyczny wobec tego, ponieważ obawiam się, że jedynie pragnie je w ciemności związać po to by rządzić wszystkimi naraz.
Przypomniało mi to koła dyskusyjne z późnego okresu projektu Piast. Zastanawialiśmy się nad tym, czy jesteśmy w stanie sformalizować każdą możliwą do podjęcia w naszej programistycznej pracy decyzję tak, że byłaby to praca czysto techniczna, gdzie wszystko robi się według podręcznika. Umożliwiłoby to opracowanie dowolnego, nawet nieistniejącego jeszcze programu poprzez usystematyzowane decyzje oparte tylko na faktach. Doszliśmy do konkluzji, że gdyby było to możliwe, to dałoby się to utrwalić w formie programu obliczeniowego.
Taki program mógłby przyjąć formę dynamicznego katalogu, który skleja program z gotowych pomniejszych klocków na bazie wywiadu z użytkownikiem. Pozostaje kwestia, czy zmieściłby się on na jakiejkolwiek maszynie?
Drugą formą, jaka przyszła nam do głowy, byłby program, który sam się rozwija na bazie wprowadzanych do niego informacji poprzez samoistne reprogramowanie maszyny, na której jest wykonywany. Taki program mógłby istnieć tak długo, jak długo nie unicestwiałby się tymi reprogramowaniami.
Z racji, że można to opisać w skrócie jako program programowania uznaliśmy, że zabawne jest określenie tego hipotetycznego bytu jako "nadprogram".
W każdym razie sam nigdy nie zastanawiałem się nad tym więcej, bo nie byłem w stanie odeprzeć wrażenia, że kryje się w tym bijekcja paradoksu zbioru wszystkich zbiorów.

Udało mi się przetrwać, bo przestałem konkurować z wszystkimi dookoła oraz wmawiać sobie, że objaw niewiedzy jest oznaką bycia gorszym. Zaakceptowałem przeciętność, zmyłem z siebie poczucie winy zostając jej arcykapłanem. Pozwól drogi czytelniku, że ciebie również rozgrzeszę.
Nie da się zapoznać z wszystkim co jest na rynku, jak również każdą ideą z kręgów intelektualnych. Nie da się w swojej głowie usystematyzować tego perfekcyjnie w sposób formalny.
Nie ma rzeczy, które każdy ekspert powinien wiedzieć. Wiedzę powszechną stanowi wszystko to, co dosłownie wie każdy w danym środowisku. Różnorodność sprawia, że dopełniamy się wzajemnie.
Żeby mieć efekty trzeba włożyć w to wysiłek. Wdrożenie rozwiązania podanego na tacy nie stanowi wiele wartości dodanej.
Programowanie obliczeniowe, podobnie jak jakakolwiek inna twórczość, jest jakościowe, jeżeli ma na celu dostarczyć produkt zaspokajający potrzeby ludzkie. A rozwiązań ludzkich problemów nie da się znaleźć w samych statystykach, do tego trzeba użyć duszy i serca.


APPENDIX A
WYBRANE FRAGMENTY DOKUMENTACJI WINDRAD

WindRad jest jedną z technologii kalkulatorowych opracowanych przez Nordhein-Westfallen Rechenwerke GmbH(NWRW).
Jego zadaniem jest dostarczanie sposobu zapisu programów w sposób uniwersalny i przetłumaczalny na dowolną programowalną maszynę cyfrową.
Program zgodny z WindRad składa się z wierszy cyfrowego tekstu. Na wiersz składają się słowa oddzielone przerwami. Przerwa jest dowolnym znakiem, który w druku robi pustą przestrzeń i jest zależna od kodowania cyfrowego tekstu użytego do zapisu programu. Przerwy na początku i na końcu wiersza nie rozróżniają programów, wielokrotne puste znaki pomiędzy słowami stanowią pojedynczą przerwę.
Wysokość liter jest rozróżnialna w WindRad. Słowa o odgórnie nadanym znaczeniu składają się z samych wielkich liter.
Wiersze opisują operacje przetwarzania danych, kształt struktur sterujących oraz zmiany przepływu sterowania. Możliwe zapisy określone są w postaci składni. Każdy wiersz ma skończoną złożoność określoną odgórnie, zależną od pierwszorzędnej składni.
Program jest wykonywany wierszami od góry w dół, a każdy wiersz słowami od lewej do prawej.
Pewne operacje nie są niezgodne z gramatyką WindRad, ale ich skutek jest niemożliwy do zdefiniowania. Takie przypadki określa się jako Grauzone(pol. szara strefa) i należy unikać doprowadzenia do nich.

Dane w Windrad podlegają typowaniu. Typy dzielą się na podstawowe i złożone. Typy złożone określa się mianem "agregat".

Typy podstawowe mają określoną wartość zeropodobną oraz porządek wartości. Wartości znajdujące się dalej w porządku uznaje się za większe.
Typy podstawowe można używać w formie wartości bezpośredniej.

Typ ZAHL służy do reprezentowania wartości całkowitoliczbowych zapisywanych za pomocą cyfr arabskich.

Typ KOMMA służy do reprezentowania liczb pseudorzeczywistych zapisywanych w formie dziesiętnej z przecinkiem oddzielającym wartość całkowitą od ułamkowej.
Bezpośrednia wartość KOMMA podlega błędowi obcięcia wynikającego z precyzji kodowania liczb przecinkowych na jaki przetłumaczony zostanie program. Wyniki operacji na wartościach KOMMA również podlegają błędom precyzji.

Oba typy liczbowe mogą reprezentować wartości ujemne zaczynające się od znaku minusa i nieposiadające przerwy między minusem, a znakami liczby.

Wartość KETTE rozpoczęta i zakończona znakiem cytatu stanowi jedno słowo.
Porządek wartości KETTE zależy przede wszystkim od długości wartości. Wartości zawierające więcej znaków są większe.
W przypadku wartości o równej liczbie znaków relacja porządku zależy od porządku znaków wynikających z użytego kodowania tekstu. Znaki używane w odgórnie określonych słowach WindRad powinny zajmować początkowe pozycje porządku.
Sugerowany porządek to:

  1. duże litery alfabetu łacińskiego
  2. małe litery alfabetu łacińskiego
  3. cyfry arabskie
  4. znaki specjalne używane jako słowa operacji tj. dwukropek, znak równości, znaki mniejsze/większe

Typ LOGIK reprezentuje wartości logiczne. Przyjmuje tylko wartość WAHR oraz FALSCH oznaczających odpowiednio prawdę oraz fałsz.
Wartością zeropodobną jest fałsz, a prawda jest większa w relacji do fałszu.
LOGIK_NULL = FALSCH
WAHR > FALSCH

Operacje na wartościach wykonywane są zgodne z typowym kierunkiem przebiegu programu tj. od lewej do prawej, ale ich wynik jest przekazywany wstecz, do lewej. Dlatego muszą zostać poprzedzone składnią, która skorzysta z wyprodukowanej wartości.
Jako operand można użyć wyłącznie wartości bezpośredniej lub symbolu. Nie można zagnieździć kolejnej operacji jako operandu.

Dla wszystkich typów podstawowych można dokonywać operacji porównania.
Operacje porównania skutkują wytworzeniem wartości typu LOGIK. Możliwe porównania to równość(=), lewe większe(>) oraz prawe większe(<).

Każdy symbol może zostać poddany operacji pobierania adresu.
Polega ono na wykorzystaniu znaku (@) po lewej stronie nazwy symbolu, bez przerwy.
Operacja wytwarza wartość adresu jako typ ZAHL.

Dla typów liczbowych można używać dwuwartościowych operacji arytmetycznych takich jak dodawanie(+), odejmowanie(-), mnożenie(*), dzielenie(/).
Pomiędzy operandami, a znakiem operacji musi występować przerwa.
Odejmowanie może występować w formie jednowartościowej w którym występuje tylko prawy operand. Produkuje ono wartość przeciwną.

Wartości KETTE można łączyć ze sobą poprzez operację konkatenacji, która funkcjonuje pod znakiem pionowej kreski(|).

Na wartościach logicznych można dokonywać operacji dwuwartościowych, czyli iloczynu(UND) i sumy(ODER). Jak również jednooperandowego zaprzeczenia logicznego(NICHT), które przyjmuje tylko prawy operand.

Dane można przetwarzać pod postacią symboli. Symbol nadaje danym semantyczną nazwę oraz umożliwia zapamiętanie wartości.
Użycie symbolu poprzedza jego deklaracja. Deklaracja określa nazwę symbolu oraz typ danych. Nazwa symbolu może składać się z dużych i małych liter oraz musi zaczynać się od małej litery.
Wiersz deklaracji symbolu rozpoczyna się słowem specjalnym DATEN.
DATEN *nazwa* *typ*
Symbole typu podstawowego tuż po deklaracji mają niezdefiniowaną wartość.
Deklarację symbolu można zakończyć słowem specjalnym KONST.
Taki symbol nie może zmienić wartości w dalszym przebiegu programu. Jego wartość musi zostać nadana w wierszu następującym po deklaracji.

Zmiana wartości symbolu może nastąpić w wyniku operacji przypisania.
Przypisanie z prawej do lewej notuje się wokół operatora := przyjmującego z lewej strony symbol, którego wartość jest zmieniana. Z prawej strony operatora podaje się wartość bezpośrednią, symbol albo operację zgodną z symbolem z lewej strony.
Wartość wyliczona z prawej strony operatora kopiowana jest do symbolu po lewej stronie.

Typy złożone agregują określony typ podstawowy.
Każdy element agregatu działa jak osobny symbol, więc może zostać użyty jako wartość jak i może mu zostać nadana nowa wartość.

Typ FOLGE reprezentuje ciągi wartości. Używa się go poprzez połączenie z typem podstawowym poprzez znak podkreślenia np. FOLGE_ZAHL.
Agregaty FOLGE wykorzystują równoodległość elementów wynikającą ze stałego rozmiaru symboli typów podstawowych oraz przyległości ich wartości w pamięci.
Deklaracja agregatu typu FOLGE wymaga określenia rozmiaru ciągu w nazwie zmiennej. Bazową cześć nazwy i liczbę elementów separuje się znakiem podkreślenia.
W ramach deklaracji wszystkie elementy ciągu uzupełniane są wartością zeropodobną.
Można ustalić wartość n pierwszych elementów ciągu używając wiersza ANFANG tuż po deklaracji agregatu FOLGE.
Za wierszem ANFANG następują wiersze z wartościami typu elementu. Każdy wiersz uzupełnia wartość pod kolejnym indeksem dolnym. Może być to wartość bezpośrednia jak i symbol.
Za ostatnią wartością wstępnego uzupełnienia umieszcza się wiersz ENDE.
Odniesienie do konkretnego elementu ciągu następuje poprzez określenie jego indeksu za znakiem podkreślenia bazowej części nazwy. Elementy indeksuje się wartościami całkowitoliczbowymi.
Indeks dolny można przekazać jako wartość bezpośrednią lub poprzez symbol. Wartość bezpośrednia nie może być ujemna. W przypadku symbolu wartość ujemna w trakcie ewaluacji ulega przesunięciu, którego wynik jest zależny od rozmiaru liczb całkowitych systemu docelowego.
Wskazanie na indeks poza rozmiarem ciągu jest przypadkiem Grauzone.

Typ ZIPP reprezentuje pary danych w relacji klucz-wartość.
Konkretny ZIPP opisuje się formacie zgodnie z przykładem.
Wstępne wartości agregatu można nadać między wierszami ANFANG- ENDE następującymi tuż po deklaracji. Poszczególne pary podaje się w wierszach w formacie według przykładu.
DATEN przykladZipp ZIPP[KETTE -> LOGIK]
ANFANG
"abc" -> WAHR
"def" -> FALSCH
"xyz" -> FALSCH
ENDE
Odniesienie do wartości pod kluczem następuje poprzez wskazanie klucza w nawiasach kwadratowych za nazwą symbolu o typie agregatu. Dostęp do wartości kluczem powinien mieć złożoność nie wyższą niż logarytmiczna.
Użycie nieistniejącego klucza do odczytu spowoduje ewaluację do wartości zeropodobnej typu wartości.

Przepływ sterowania programu można kształtować za pomocą struktur sterujących i podprogramów.
Symbole zadeklarowane wewnątrz struktur sterujących przestając funkcjonować za ich zamknięciem. Ich nazwy nie mogą być takie same jak nazwy symboli zadeklarowanych w wierszach poprzedzających strukturę sterującą.

Struktury wyboru służą do wybiórczego wykonywania wierszy programu w zależności od jego stanu.

Struktura FLIPPER pozwala na wykonanie operacji od wybranego wiersza w zależności od wartości wejściowej.
Wejście do struktury FLIPPER może być tylko wartości ZAHL.
Strukturę otwiera wiersz ze słowem specjalnym FLIPPER i następującą po nim wartością typu ZAHL. Może być ona zarówno symbolem jak i wartością bezpośrednią.
Wewnątrz struktury znajdują się wiersze operacji oraz wiersze REIN oznaczające początek operacji dla danej wartości wejścia.
Wiersz REIN wymaga podania bezpośredniej wartości typu ZAHL tuż za słowem REIN.
Wartości poszczególnych REIN-ów nie mogą się powtarzać. Pierwszy wiersz wewnątrz FLIPPERA musi być REIN-em.
Po dopasowaniu wejścia do REIN-u wykonane zostaną wszystkie wiersze za REIN-em aż do końca FLIPPER-a. Wcześniejsze przekierowanie sterowania na zewnątrz struktury FLIPPER jest możliwe za pomocą wiersza RAUS.

Opcjonalnie za wartością dla REIN można umieścić drugorzędną składnię powodującą przepływ sterowania na zewnątrz.
Strukturę FLIPPER zamyka się wierszem z odwróconym słowem specjalnym - REPPILF.

Struktura WENN pozwala na wykonanie operacji jeżeli spełniony zostanie warunek.
Struktura rozpoczyna się od wiersza zaczynającego się słowem WENN po którym występuje wartość bezpośrednia, symbol albo operacja typu LOGIK.
Warunek uznaje się za spełniony jeżeli ewaluuje się do wartości WAHR.
Blok warunkowy zamyka się wierszem NNEW, DOCH albo DOCH WENN. Wiersz DOCH otwiera blok, który wykonuje się jeśli poprzedni warunek nie został spełniony. Wiersz DOCH WENN pozwala na zdefiniowanie kolejnego bloku, którego sprawdzenie nastąpi jedynie jeśli poprzedni warunek nie został spełniony.

Struktury iterujące służą do wielokrotnego wykonywania tych samych wierszy.

Struktura BIS służy do n-krotnego wykonania bloku programu.
Podstawowa składnia przyjmuje liczbę iteracji. Wiersz rozpoczynający można rozszerzyć składnią VON określającą wartość pierwszego numeru iteracji, domyślnie jest to jeden.
Można również rozszerzyć ją składnią ALS, która określa nazwę tymczasowego symbolu ZAHL przechowującego wartość aktualnej iteracji. Nazwa symbolu nie może się pokrywać z wcześniej zadeklarowanymi i istnieje tylko do końca struktury.
BIS 10
BIS 15 VON 5
BIS 10 ALS iteracja
BIS 9 VON 1 ALS iteracja
Strukturę zamyka się wierszem ze słowem SIB.

Każdy blok składni można wyizolować zamykając go w podprogram.
Deklaracja podprogramu rozpoczyna się słowem UNTERPROGRAMM. Po nim następuje opcjonalny typ wartości zwrotnej podprogramu. Dalej jest nazwa podprogramu, która podlega tym samym regułom co nazwy symboli. Nazwy zarówno symboli jak i podprogramów nie mogą się dublować.
W kolejnych wierszach deklaruje się symbole stanowiące parametry programu. Każdy wiersz składa się z nazwy symbolu parametru i jego typu. Nazwa parametru nie może być tożsama nazwie podprogramu.
Po liście parametrów następuje wiersz STARTE za którymi znajdują się wiersze instrukcji podprogramu. Za ostatnią instrukcją umieszcza się wiersz ENDE.
Wewnątrz podprogramu nie można deklarować kolejnych podprogramów. Nie można deklarować podprogramów wewnątrz struktur sterujących.

Słowo specjalne ZUR funkcjonuje jako zmiana przepływu sterowania. Składnia ta powoduje wyjście na zewnątrz wykonywanego podprogramu, czyli tak zwany powrót.
W przypadku funkcji zwracającej wartość funkcjonuje również jako symbol. Wartość do niego przypisana stanowi wartość zwrotną funkcji. W przypadku przypisywania od prawej do lewej ze słowem ZUR po lewej, po prawej stronie może wystąpić jedynie wartość bezpośrednia lub symbol.

W podprogramie funkcjonują wyłącznie symbole zadeklarowane jako jego parametry oraz symbole zadeklarowane wewnątrz wierszy podprogramu.
Nazwa symbolu w podprogramie może być taka sama jak w innych podprogramach oraz wierszach głównego programu.

Chcąc wykonać podprogram należy rozpocząć wiersz słowem specjalnym TUN.
Wywołanie może nastąpić wyłącznie za deklaracją podprogramu. Za słowem TUN podaje się nazwę podprogramu i bez przerwy otwiera nawiasy w których podaje się wartości argumentów oddzielone przerwami.
Jako argumenty podprogramu można przekazać wyłącznie symbole i wartości bezpośrednie. Wartość symboli przekazanych jako argumenty jest kopiowana do symboli zadeklarowanych jako parametry podprogramu.
Wartość zwrotną podprogramu można skopiować do symbolu używając operatora =: za wywołaniem podprogramu i symbolu po prawej stronie tego operatora.

Istnieje szereg podprogramów, które powinny być dostępne do wywołania w każdym programie i dostosowane pod system docelowy.

Grupa podprogramów pamięciowych służy do tymczasowego przydzielania bloków pamięci przez system docelowy.
Wśród nich znajdują się podprogramy do zapisu oraz odczytu wartości każdego typu podstawowego z adresu wskazanego jako typ ZAHL.

Podprogram ZEIT służy do pobierania czasu, który upłynął od początku uruchomienia programu.
Podprogram nie deklaruje żadnych parametrów.
Podprogram zwraca ciąg wartości typu FOLGE_ZAHL, którego rozmiar i znaczenie elementów zależą od systemu docelowego.

Program tłumaczący może udostępniać również podprogramy charakterstyczne dla systemu docelowego.

APPENDIX B
WYBRANE FRAGMENTY DOKUMENTACJI WISŁA 64

Wisła 64 udostępnia ponad 64 tysiące adresowalnych komórek pamięci.

W przypadku wartości całkowitoliczbowych cyfry binarne poszczególnych oktetów są kodowane od prawej do lewej jako od najmniej do najbardziej znaczącej.

Instrukcje programu Wisła 64 kodowane są jako kolejne binarne oktety w pamięci. Każda instrukcja koduje operację w pierwszym oktecie oraz może użyć od 0 do 3 następujących oktetów jako operandy.
Cyfry oktetu operacji opisane są od lewej do prawej. Pierwsze cztery cyfry binarne kodują bazową operację w formie liczby porządkowej. Kolejne cztery to flagi charakterystyki operacji. Każda bazowa operacja wspiera inną kombinację charakterystyk.
Model programowy pozwala na użycie dwóch rejestrów. Rejestru roboczego oraz rejestru szczytu stosu wykonania. Rejestr szczytu stosu wykonania zawiera adres bloku pamięci przechowującego informacje o ramkach procedur oraz danych z nimi związanych.
Używany rejestr koduje się na piątej cyfrze binarnej w taki sposób, że 0 to rejestr roboczy, a 1 to rejestr stosu.
Cyfra numer 6 określa w jakim zakresie przetwarza się rejestr. Instrukcja może działać w trybie pełnym(0) albo połowicznym(1), czyli odpowiednio dwu albo jednooktetowym.
Cyfra numer 7 oznacza, czy rejestr używany jest w trybie wartości(0) czy trybie wskaźnika(1). Tryb wartości to operowanie na wartości rejestru wprost. Tryb wskaźnika oznacza, że wartość w rejestrze wyznacza adres pod którym znajduje się wartość do użycia.
W trybie wskaźnika wymagane jest podanie dodatkowego oktetu operandu tuż za oktetem operacji, który koduje przesunięcie względem adresu pod rejestrem. Wartość operandu kodowana jest w formacie uzupełnień do dwóch.
Ostatnia cyfra oznacza, czy operand główny jest adresem(0) czy wartością(1). Operand adresowy zawsze zajmuje dwa oktety, operand wartościowy może być jednooktetowy, jeżeli wybrano przetwarzanie w trybie połowicznym.
Dokładne działanie zależne jest od operacji bazowej.

Program na Wisłę 64 można zapisywać w postaci notacji pomocniczej. Istnienie programu przekładającego tę notację na kodowanie obrazu programu jest zależne od systemu na którym przetwarzany jest zapis. Każda instrukcja zapisywana jest w osobnym wierszu.
Można tworzyć wiersze funkcjonujące jako alias adresu. Taki wiersz rozpoczyna się znakiem zakreślonego a - @. Wartość aliasu jest wyliczana w trakcie kodowania obrazu programu.
Program kodujący powinien umożliwić określenie wartości adresu pierwszej instrukcji programu. Względem tej wartości przeliczane są wszystkie aliasy powstałe w ramach oznaczenia wiersza. Możliwe jest również nadanie stałej wartości aliasu adresowego. Każda operacja bazowa ma swój mnemonik w notacji pomocniczej. Mnemoniki pisze się w formie małych liter.
Notacja pomocnicza pozwala na korzystanie z tzw. adresów pomocniczych - auxilar. Notuje się je w skrócie dużych liter AUX za którymi znajduje się liczba porządkowa.
Możliwe jest bezpośrednie kodowanie wartości w obrazie programu. Służą do tego wiersze zaczynające się od znaku krzyżyka(#). Kodują one tyle oktetów ile jest minimalnie potrzebne dla zapisanej wartości. Domyślnie wartości są w formie dziesiętnej np. #127, ale mogą być również zapisywane w formie binarnej np. #b1001 albo heksadecymalnej np. #hf0a1.
Zakodowany obraz programu powinien zawierać dodatkowe podwójne sekwencje zerowych oktetów o liczbie równej największej liczbie porządkowej użytej jako adres pomocniczy. Oktety te powinny znaleźć się za oktetami kodującymi ostatnią instrukcję.

Wiersz instrukcji rozpoczyna się od mnemonika operacji bazowej. Po nim następuje mnemonik rejestru(R - roboczy, S - stosu). Nie każda operacja bazowa używa rejestru.
Chcąc użyć rejestru w trybie adresowym należy tuż za jego mnemonikiem, bez przerwy umieścić znak zakreślonego a oraz wartość przesunięcia. Wartość przesunięcia przyjmuje wartości od -128 do 127. Kolejnym możliwym słowem jest wartość operandu głównego. Tryb połowiczny wymusza się poprzez prefiks operandu znakiem dużego P. Wartości bezpośrednie w trybie połowicznym muszą być jednooktetowe.
Operand adresowy zapisuje się jako wartość liczbową lub wyciąga z aliasu.

Operand wartościowy poprzedza się znakiem krzyżyka(#). Wartości można podawać tak samo jak w przypadku wierszy kodujących dane z tym, że nie mogą być większe niż na dwa oktety.
Możliwe jest użycie aliasu jako operacja na dosłownej wartości adresu, a nie wartości znajdującej się pod nim.
Notacja pomocnicza udostępnia również specjalną składnię "rel" służącą do tworzenia wartości względnej do aliasu adresu na potrzeby skoków. Wartość liczona jest względem końca instrukcji i zmniejszana o jeden, aby uwzględnić jeden oktet instrukcji skoku, która ma ją wykorzystać.

lista operacji:

nazwakodmnemoniktryby rejestrutryby operandu
pusta operacja0nicnie dotyczynie dotyczy
wstawienie do rejestru1wstwartość/wskaźnikadres/wartość
przechowanie w pamięci2przewartość/wskaźnikadres
iloczyn binarny3orazwartośćadres/wartość
suma binarna4lubwartośćadres/wartość
negacja binarna5niewartośćnie dotyczy
dodawanie6dodwartośćadres/wartość
odejmowanie7odewartośćadres/wartość
mnożenie8mnwartośćadres/wartość
Skok bezwarunkowy9sknie dotyczynie dotyczy
porównanie10porwartość/wskaźnikadres/wartość
Skok gdy nierówne11sgnnie dotyczynie dotyczy
Skok gdy mniejsze12sgmnie dotyczynie dotyczy
Wykonanie procedury13czynnie dotyczynie dotyczy
Powrót z procedury14pwrnie dotyczynie dotyczy
Zatrzymanie maszyny15stopnie dotyczynie dotyczy

Pusta operacja skutkuje przejściem do następnej instrukcji. Wykonuje puste cykle zegara bez wpływu na stan pamięci i rejestrów.

Operacje binarne oraz arytmetyczne zapisują otrzymany wynik w użytym rejestrze.

Operacje skoku używają wartości rejestru roboczego jako przesunięcie względne w oktetach. Przesunięcie następuje względem końca instrukcji skoku.
Skoki "gdy" bazują na wyniku ostatniej operacji porównania. Operacja porównania porównuje rejestr do operandu, więc przykładowo skok gdy mniejsze dokona skoku, gdy w ramach ostatniego porównania wartość rejestrowa była mniejsza niż wartość operandowa.

Operacja wykonania procedury wykorzystuje wartość w rejestrze roboczym jako adres pod którym znajduje się pierwsza instrukcja procedury.
Operacja wykonania procedury powoduje wpisanie adresu początku następnej instrukcji na wierzch stosu i zwiększenie jego rejestru o dwa. Analogicznie operacja powrotu korzysta z dwóch oktetów poniżej wartości rejestru stosu jako adres skoku. Następnie zmniejsza wartość rejestru stosu o dwa.

Operacja zatrzymania maszyny powoduje całkowite zatrzymanie przebiegu przetwarzania instrukcji.

Pusta operacja skutkuje przejściem do następnej instrukcji. Wykonuje puste cykle zegara bez wpływu na stan pamięci i rejestrów. Operacje binarne oraz arytmetyczne zapisują otrzymany wynik w użytym rejestrze.
Operacje skoku używają wartości rejestru roboczego jako przesunięcie względne w oktetach. Przesunięcie następuje względem końca instrukcji skoku.
Skoki "gdy" bazują na wyniku ostatniej operacji porównania. Operacja porównania porównuje rejestr do operandu, więc przykładowo skok gdy mniejsze dokona skoku, gdy w ramach ostatniego porównania wartość rejestrowa była mniejsza niż wartość operandowa. Operacja wykonania procedury wykorzystuje wartość w rejestrze roboczym jako adres pod którym znajduje się pierwsza instrukcja procedury.
Operacja wykonania procedury powoduje wpisanie adresu początku następnej instrukcji na wierzch stosu i zwiększenie jego rejestru o dwa. Analogicznie operacja powrotu korzysta z dwóch oktetów poniżej wartości rejestru stosu jako adres skoku. Następnie zmniejsza wartość rejestru stosu o dwa.
Operacja zatrzymania maszyny powoduje całkowite zatrzymanie przebiegu przetwarzania instrukcji.
Zapis wartości rozpościerających się na szereg adresów następuje zgodnie ze wzrostem adresów. Oktety uszeregowane są przeciwnie do adresacji pod względem wyższości. W notacji pomocniczej dwuoktetowych wartości liczbowych lewy oktet zawiera bardziej znaczącą część, w tym cyfrę znaku pod najbardziej lewą cyfrą. Operacja połowiczna na wartości rejestru wpływa tylko na prawy oktet. Operacja połowiczna na pamięci traktuje wartość pod adresem jako jednooktetową.

Po uruchomieniu Wisła 64 rozpoczyna wykonywanie instrukcji począwszy od adresu zerowego.

Ostatnie 32 oktety pamięci są służą do programowego monitorowania oraz kontroli podstawowego funkcjonowania maszyny.

Maszyna zlicza swój czas działania i udostępnia go w trzech licznikach kodujących nieujemne wartości całkowite
#hff80 - dwuoktetowy licznik mikrosekund, który przekręca się co 10 tys. mikrosekund
#hff82 - dwuoktetowy licznik setnych sekundy, który przekręca się co 600 sekund
#hff84 - jednooktetowy licznik jednej szóstej godzin, który przekręca się co 42 godziny

APPENDIX C
WYBRANE FRAGMENTY DOKUMENTACJI DRZWI

Drzwi to program nadzorujący dedykowany na maszyny kalkulujące Wisła 64 oraz podobnej mocy obliczeniowej.
To również ekosystem w którym programy mogą być wykonywane współbieżnie. Dostarcza on szeregu funkcjonalności ogólnego zastosowania, dzięki czemu programy nie muszą powielać powszechnych procedur.

Programy wykonywane pod nadzorem Drzwi mają przydzielane segmenty pamięci. Pierwszy program uruchomiony pod nadzorem znajduje się w segmencie zaraz za segmentem programu nadzorowania. Na końcu puli pamięci znajdują się oktety, które program nadzorujący przydziela na żądanie. Taka pamięć może być współdzielona między programami.
Segment programu wykonywanego składa się z następujących części.

  1. tabela adresów procedur
  2. instrukcje główne
  3. adresy pomocnicze
  4. stos wykonania programu

Dla wszystkich procedur znajdujących się w obrazie programu należy utworzyć tabelę adresów początkowych.
Do wywołania procedury należy użyć adresu rekordu w tabeli adresów początkowych procedur. Dzięki temu program nadzorujący Drzwi może przeliczyć wartości adresów po umieszczeniu obrazu w pamięci operacyjnej.

Wykonanie programu wymaga wskazania jego obrazu. Obraz programu wykonywalnego pod programem nadzorującym Drzwi musi zawierać nagłówek danych.

  1. wartość adresu pierwszej instrukcji programu - 2 oktety
  2. adres tabeli adresów procedur adekwatny do adresu pierwszej instrukcji - 2 oktety
  3. liczba procedur w tabeli - 1 oktet
  4. liczba oktetów na adresy pomocnicze - 1 oktet

Schemat notacji pomocniczej Wisła 64 z której wygeneruje się obraz programu.

#h0100
#@tabelaAdresowProcedur
#02
#0a
[...]
@instrukcje
[...]
stop
@tabelaAdresowProcedur
@adresProcedury1
#@procedura1
@adresProcedury2
#@procedura2
@procedury
@procedura1
wst R #0
pwr

Operandy adresowe większe niż 84(h) są rekalkulowane względem adresu pierwszej instrukcji obrazu po jego umieszczeniu w segmencie pamięci.

Program oraz jego procedury wykonywane pod nadzorem Drzwi powinny dokonywać transferu wartości w następujący sposób. Parametry programu muszą mieć określoną kolejność. Ich wartości należy odłożyć na stos w tej właśnie kolejności przed wykonaniem procedury.
Wartość zwrotna programu musi zostać umieszczona w rejestrze roboczym przed powrotem z procedury.

Ekosystem Drzwi dostarcza sposobu kodowania oraz procedur przetwarzania liczb przecinkowych.
Jest to zmiennoprzecinkowy format o podstawie dwójkowej z rozróżnieniem dodatnie/ujemne, 9-cyfrową mantysą i 6-cyfrową eksponentą.
Pierwsza cyfra od lewej koduje kierunek względem zera. Wartość 0 oznacza liczby dodatnie, a 1 ujemne.
Cyfry od drugiej do dziesiątej kodują mantysę. Każda cyfra to składnik kolejnej ujemnej potęgi dwa począwszy od dwa do minus pierwszej. Cyfry od jedenastej do szesnastej kodują wykładnik w formacie uzupełnień do dwóch z najmniej znaczącą najbardziej prawą cyfrą.

Program nadzorujący Drzwi dostarcza procedury wszechstronnego użytku.
Pozycje poszczególnych procedur bazowych w tabeli adresów są stałe. Rozszerzenie do programu kodującego nadaje im aliasy o stałych wartościach.

Aliasy procedur w notacji pomocniczej:

Drzwi-Zmiennoprzecinkowe-dodaj
Drzwi-Zmiennoprzecinkowe-odejmij
Drzwi-Zmiennoprzecinkowe-mnoz
Drzwi-Zmiennoprzecinkowe-dziel

Drzwi-Pamiec-rezerwuj
Drzwi-Pamiec-zapisz
Drzwi-Pamiec-czytaj
Drzwi-Pamiec-zwolnij

Drzwi-DrzewoBinarne-rezerwuj
Drzwi-DrzewoBinarne-wstaw
Drzwi-DrzewoBinarne-znajdz
Drzwi-DrzewoBinarne-zwolnij

procedura Drzwi-DrzewoBinarne-rezerwuj
parametr 1
rodzaj wartości przeszukiwania oraz rodzaj wartości w liściach - 1 oktet pierwsza połowa oktetu koduje rodzaj przeszukiwania, a druga rodzaj wartości w liściach
rodzaje danych:
1 - liczba całkowita
2 - liczba zmiennoprzecinkowa
3 - łańcuch znaków

wartość zwracana
adres pod którym znajdują się dane drzewa

procedura Drzwi-DrzewoBinarne-wstaw
parametr 1
wartość wyszukiwania - 2 oktety

parametr 2
wartość liścia - 2 oktety

wartość zwracana
brak

procedura Drzwi-DrzewoBinarne-znajdz
parametr 1
wartość przeszukiwania - 2 oktety

wartość zwracana
znaleziona wartość lub zera w przypadku nieistniejącej wartości wyszukiwania