sobota, 31 października 2015

Jak żyć?

Wybory się odbyły. Wszyscy są na świeżo z polityką więc nadarza się fajna okazja by przedstawić moje poglądy w tym temacie. Dlaczego po, a nie przed wyborami? Dlatego, że zamierzam przedstawić moje poglądy, a nie nawoływać byś zmienił swoje.

Jestem chrześcijaninem i libertarianinem. Niektórzy mówią, że to się ze sobą nie łączy. Nie do końca rozumiem ten tok rozumowania. Przecież Bóg stworzył człowieka by ten miał wolną wolę. Oczywiście zły wybór ma swoje konsekwencje ale niewątpliwie wolność jest naszą naturą. A libertarianizm traktuje właśnie o wolności. Nie mówi on o tym co jest dobre, a co złe. Mówi tylko o społeczeństwie, "w którym żadna ludzka własność - czy to własność osoby czy rzeczy realnych - nie podlega agresji ze strony innych, nie jest przez innych naruszana czy poddawana jakiejś obcej ingerencji" - Etyka wolności, Murray N. Rothbard, s. 124.

I zgadzam się, że czasami przekroczenie wolności może być moralne. Kiedy? Na przykład widząc umierające z głodu dziecko na ulicy i nie mając pieniędzy kradzież w celu ratowania życia byłaby uzasadniona moralnie. Lecz i wtedy godziłbym się ponieść konsekwencje tego czynu. W końcu dokonałbym kradzieży. Jak pisze Rothbard:

"Nie chodzi nam o to, czy bycie kłamcą, bycie dobrym człowiekiem, rozwijanie własnych zdolności lub bycie miłym lub podłym dla sąsiadów jest moralne bądź nie. Interesują nas jedynie takie kwestie "etyki politycznej", jak właściwa rola przemocy, sfera praw albo definicje przestępczości i agresji" (Etyka wolności, Murray N. Rothbard, s. 259).

Definicja wolności

Pisząc o wolności najpierw postaram się ją zdefiniować. Będę się dalej do niej wielokrotnie odnosił więc jest ważne byśmy ustalili najpierw pojęcia.

Moją wolność rozumiem jako brak agresji wobec mojej osoby i mojej sprawiedliwie zdobytej własności. I znów jak pisze Rothbard: "... definicja wolności lub swobody, aby została rozumiana jako "brak naruszenia ludzkiej sprawiedliwej własności", musi zostać rozjaśniona tak, by sprawiedliwość wskazywała na tytuł własności do własnej osoby, do przekształconej (niczyjej) własności oraz do owoców dobrowolnych wymian na nich zbudowanych." (Etyka wolności, Murray N. Rothbard, s. 125)

Wszyscy wiemy jak w kontekście tej definicji plasuje się system polityczny, w którym żyjemy zwany demokracją. Każdy wyznający tę samą definicję wolności co ja zdaje sobie zapewne sprawę, że demokracja to tak naprawdę agresja większości. A dotykając tego tematu nie sposób od razu nie wspomnieć o wyborach.

Demokracja?

Skoro demokracja to agresja większości to wybory są narzędziem do jej wywoływania. Również jeśli głosujesz za kimś kto chce zadać jej kres dokonujesz agresji przeciwko ludziom, którzy chcą żyć w tym systemie. I to pomimo tego, że w libertariańskim społeczeństwie mogliby sobie żyć jak chcą. Nie czynisz niczego złego, gdy ktoś tobie narzuca sposób życia. Natomiast czynisz źle, gdy narzucasz go innym.

Popularne stwierdzenie - mam nadzieję, że nie u libertarian - kto nie głosuje ten nie ma prawa krytykować jest istnym nonsensem. Wyobraźmy sobie sytuację, w której napastnik z bronią terroryzuje ofiarę lecz daje jej również możliwość poprawy swojej sytuacji poprzez agresję na innej osobie. Mógłby on wystosować takie oto słowa w kierunku ofiary:

"Nie będę Cię dłużej nękał jeśli ukradniesz pani X torebkę i przyniesiesz ją do mnie".

Mam nadzieję, że porównanie jest jasne. W tym przypadku agresorem jest rząd, który daje nam możliwość zniesienia agresji poprzez ustanowienie innego rządu w tym również dla ludzi, którzy go nie chcą. Dlaczego jeśli ofiara nie zechce skorzystać z takiej niemoralnej propozycji, miałaby nie móc dłużej krytykować oprawcy?

Jak zatem cokolwiek można zmienić? Należy pokazać i przekonać ludzi, że można żyć bez tego całego cyrku. Możemy ignorować rząd kompletnie i niezależnie od tego co stanowi prawo, postępować słusznie. Rząd bardzo chce być potrzebny bo tylko tak może zostać wybrany.

Motywacja

Zmiany jeśli mają nastąpić to muszą nastąpić oddolnie. I nie chodzi mi o to by teraz każdy poruszał się tylko po prywatnych działkach i tylko prywatnym samochodem itd. Jak pisze Jakub Wozinski, to by skutkowało narażeniem całego ruchu libertariańskiego na śmieszność. Ludzie traktowaliby libertarian jak swego rodzaju Amiszów, którzy żyją w swoim świecie. Nie znaczy to by naszą motywacją było wykazać, że rząd (policja, sądy, wojsko itp.) nie daje sobie z niczym rady. Wydaje mi się, że motywacją powinno być zbudowanie takich struktur, które lepiej będą sobie w tych zakresach radzić niż państwo.

Znacznie lepiej jest pokazać, że człowiek dobrze sobie radzi bez pomocy państwa. Jeśli prowadzisz biznes to pokaż, że możesz go prowadzić bez dotacji. Jeśli masz wybór by nie korzystać z państwowej służby zdrowia to nie korzystaj, jeśli możesz poradzić sobie bez policji i sądu to tym lepiej, jeśli musisz płacić ZUS to jeśli jesteś w stanie pokaż, że nie chcesz od niego ani złotówki itd. Rozumiem doskonale, że ludzie są w różnej sytuacji. Czasami człowiek nie widzi innego wyjścia. Potrafię sobie wyobrazić libertarianina "pracującego" w urzędzie skarbowym albo w policji. Jeśli jesteś w takiej sytuacji to przede wszystkim staraj się z niej wydostać i czyń jak najmniej szkody.

Raz jeszcze podkreślę, że nie powinno być celem doprowadzenie do bankructwa państwa, UE czy ZUSu. Celem nie jest by wykazać, że policja jest nieudolna, a sądy skorumpowane. Celem jest nauczenie ludzi, że można sobie radzić bez tego i to znacznie lepiej (albo przynajmniej z czystym sumieniem). I nie buntujmy się przeciwko płaceniu danin. Płacąc je nie czynimy niczego złego. To ludzie narzucający nam ich płacenie źle czynią. Natomiast krytykujmy ile się da. Jeśli podatki wykończą ci biznes to pokaż to. Jeśli płacenie ZUSu wpędza cię w biedę opisz to.

Strach

Strach paraliżuje zmiany. Ludzie, w mojej ocenie, boją się, że bez ZUSu ludzie wylądują na ulicy, boją się, że bez policji będzie chaos, a bez (państwowego) wojska to...

Oczywiście możemy powiedzieć, że skoro tak dużo ludzi godzi się na płacenie ZUSu by nie było innych na ulicach to też chętnie sami im pomogą bez ZUSu. Oczywiście możemy powiedzieć, że będzie mniej ludzi na ulicach niż jest dzisiaj bo ludzie biedniejsi w końcu będą mogli zaspokoić ważniejsze potrzeby niż emerytura jeśli im nikt nie będzie zabierał pieniędzy. Jeśli będą mieli co jeść i za co się leczyć zamiast odkładać na emeryturę to całkiem możliwe, że dorobią się znacznie więcej i znaczniej dłużej pożyją itd.

Możemy powiedzieć, że w najgorszym przypadku człowiek będzie pracował przez całe życie. A to myślę, że w ogóle powinien być cel każdego chrześcijanina zgodnie z tym, że "kto nie pracuje ten niechaj i nie je". Praca jest nieodłączną częścią życia człowieka, a nie tylko jego etapem ale to temat na inną okazję.

Tylko jest jedno ale. To są tylko słowa. Być może i logiczne i nie pozostawiające żadnej innej logicznej możliwości ale nadal nie jest to coś co można zobaczyć. Dlatego ważne jest by wszyscy mogli się przekonać, że można żyć z własnej woli bez ZUSu i pomagać innym, którzy sobie nie radzą. Nikt w cale nie musi liczyć na państwo.

To samo można mówić o pieniądzu. Państwo wcale nie musi go kontrolować. Możemy mówić, że pieniądz jest jak sejf bo przechowuje jakąś wartość i powinniśmy mieć możliwość wyboru najbezpieczniejszego w naszej ocenie sejfu, a nie tylko takiego, które państwo nam wskaże i do którego ono samo ma dostęp. Może nam przecież zabrać część jego zawartości poprzez inflację. Tylko, że znowu to wszystko na nic się nie zda jeśli nie pokażemy, że można żyć bez państwowego pieniądza.

Podsumowanie

Moje poglądy na rządy są jednoznaczne. Jakie by one nie były zawsze oznaczają agresję, a więc ograniczenie mojej wolności. Rozumiem też, że większość chce żyć w ten sposób ale ja nie zwracam uwagi na rząd. Ignoruję go na tyle na ile mogę sobie pozwolić. Płacę wszystko co na mnie wymusza i nie dbam o to. Mogą zabrać mi wszystko co mam. Nie żyję po to by być bogatym ani by żyć wygodnie. Nie głosuję i nie wybieram rządu. Staram się żyć w zgodzie z tym co uznaję za słuszne, a nie w zgodzie z tym co stanowi prawo. Jeśli naprawdę chcesz by ludzie zechcieli być wolni to najpierw zacznij od siebie.

poniedziałek, 6 kwietnia 2015

Tam gdzie statyczne typowanie nie wystarcza...

tam pojawia się... No właśnie, co? Zanim o tym, najpierw napiszę trochę o problemach z typowaniem. Statyczne typowanie daje nam pewność, że nigdy nie przekażemy innego typu do funkcji niż tego oczekuje. W językach dynamicznych często musimy pisać dodatkowe testy jednostkowe aby mieć jakąś dozę pewności, że dana funkcja zachowa się poprawnie dla niepoprawnego typu. Dla przykładu co ma zrobić funkcja zliczająca elementy w tablicy jeśli zamiast tablicy przekażemy jej liczbę? Mamy kilka możliwości:

  • zwracamy 0 - zazwyczaj nie wywoła to od razu większych problemów, gdyż kod wykorzystujący taką funkcję jest raczej przygotowany na obsługę pustej tablicy. Niestety w ten sposób ukrywamy błąd, którym jest oczywiście przekazanie liczby zamiast tablicy. Znalezienie go przy takim rozwiązaniu może być kłopotliwe.
  • zwracamy ujemną wartość - ujemna liczba elementów tablicy nie ma sensu więc może to sygnalizować jakiś błąd. Problem w tym, że wszędzie, gdzie używamy takiej funkcji musielibyśmy się ubezpieczyć na taką ewentualność. Tutaj znów potrzebowalibyśmy sporej liczby testów jednostkowych by jakoś to wymusić. Jeżeli tego nie zrobimy to istnieje ryzyko, że ktoś np. będzie coś przemnażał przez ujemną liczbę co znów może być trudne do wykrycia (choć łatwiejsze niż w przypadku zwracania 0).
  • rzucamy wyjątek - błąd ukaże się nam od razu więc będzie łatwiejszy w lokalizacji. Tyle, że znów musielibyśmy się przed tym zabezpieczyć w miejscach, gdzie wykorzystujemy taką funkcję. Jeżeli tego nie zrobimy to cała aplikacja się po prostu wywali. Zatem i w tym wypadku potrzebujemy sporej liczby testów.

Wszystkie te rozwiązania mają jedną zasadniczą wadę w stosunku do statycznego typowania. Musimy dopisać sporą liczbę testów by móc wykryć błędy przed uruchomieniem aplikacji. W językach ze statycznym typowaniem, błąd zostanie wychwycony już przez kompilator/interpreter więc testy dla takich problemów są zbędne. No ale czy zawsze?


Typ a wartość

Czasami mimo używania statycznych typów i tak będziemy mieli problem. Dla przykładu weźmy sobie funkcję liczącą średnią z listy liczb. Czyli przyjmujemy sobie taką listę liczb, sumujemy jej elementy i dzielimy przez ich liczbę. A co jeśli przekazana lista jest pusta? Mielibyśmy dzielenie przez 0. Statyczne typowanie nas przed tym nie ustrzeże bo pusta lista to też lista (jest tego samego typu, tak jak 0 i 1). Mamy więc dwa wyjścia. Albo korzystamy z tych samych rozwiązań, które opisałem wyżej albo tworzymy dwa typy danych: jeden to lista pusta, a drugi to lista niepusta. Problem z dwoma typami danych jest taki, że pisanie w ten sposób byłoby raczej karkołomne. W Haskellu wszędzie, gdzie zwracaliśmy np. [Int] teraz mielibyśmy coś w rodzaju Either EmptyList (NotEmptyList Int). Wychodzi więc na to, że nie pozostaje nam nic innego jak pisanie testów i modlenie się przed wrzuceniem tego na produkcję, że wszystko zadziała. Na szczęście mamy jeszcze jedno wyjście (przynajmniej w Haskellu).


LiquidHaskell

LiquidHaskell to w skrócie dodatkowy walidator kodu Haskella, który umożliwia nam pisanie w komentarzach pewnych dodatkowych logicznych warunków co do wartości danego typu. Np. w powyższym przykładzie moglibyśmy dla funkcji liczącej średnią zapisać warunek, że nie przyjmuje ona listy pustej. Warunek ten będzie sprawdzony przed uruchomieniem aplikacji, a oto właśnie nam chodzi. Tylko, że jak to działa?

Najlepiej będzie pokazać to na przykładzie. Weźmy sobie przykładową implementację gry FizzBuzz. Gra polega na wymawianiu kolejnych liczb ale jeśli są one podzielne przez 3 to mówimy "Fizz", jeśli przez 5 to "Buzz", a jeśli przez 3 i 5 to "FizzBuzz". Oto przykładowa implementacja w Haskellu:

Przykładowy wynik działania programu:

Implementacja jest bardzo prosta. Jest też bardzo podatna na błędy. Np. weźmy sobie funkcję numberType i zamieńmy Fizz, Buzz, FizzBuzz na Normal i. Program skompiluje się bez problemu, a aplikacja będzie działać błędnie.

Teraz przyjrzyjmy się implementacji z wykorzystaniem LiquidHaskell:

Różni się ona tylko komentarzami, które są interpretowane przez program o nazwie liquid, który jest dostępny po zainstalowaniu LiquidHaskell. Co możemy z nich wyczytać? Dla przykładu weźmy tę linijkę: Normal (i :: {v:Int | v mod 3 /= 0 && v mod 5 /= 0}). Mówi ona o tym, że konstruktor Normal może przyjąć liczbę i, która jest typu Int ale tylko taką, która nie jest podzielna przez 3 i przez 5. No to wypróbujmy to. Spróbujmy zrobić tak jak poprzednio czyli w funkcji numberType we wszystkich warunkach wpisać Normal i. Po tej zmianie uruchamiamy liquid fizzbuzz.hs i otrzymujemy:

liquid pokazuje nam, że w liniach 31, 32, 33 (czyli tam gdzie zmienialiśmy) nie zgadzają się typy. Dla przykładu w linii 31 oczekiwano typu Int, który nie jest podzielny przez 3 ani przez 5 ale nic na to nie wskazuje. Zauważmy, że wszystkie dane do programu są wczytywane w trakcie jego działania. Zatem liquid musi interpretować wszystkie ify w naszym kodzie by móc czegokolwiek dowodzić. Nie wymaga on więc od nas innego pisania kodu niż zwykle.


Podsumowanie

Jak widać LiquidHaskell to potężne narzędzie. Oczywiście wydłuża to sprawdzanie (i pisanie) kodu ale jak się okazuje w praktyce nie potrzeba wcale dokładać wielu dodatkowych warunków by pozbyć się sporej liczby testów jednostkowych. Taka koncepcja jest szerzej znana jako dependent types i istnieje nawet kilka języków, które takie typy posiadają. Problemem jest oczywiście czas kompilacji takich programów i jak się wydaje LiquidHaskell stara się ten problem rozwiązać. Więcej można poczytać w samouczku.

środa, 1 kwietnia 2015

BŁĄD: znak sekwencją bajtów 0xe2 0x80 0x9e kodowany w "UTF8" nie ma równoważnego w kodowaniu "LATIN2"

Jeżeli ktoś kiedyś natknął się na taki błąd to oznacza, że jego aplikacja powstawała co najmniej 20 lat temu. Komunikat oznacza mniej więcej tyle, że łączy się ona z bazą używając kodowania jednobajtowego latin-2 czy też iso-8859-2, a baza danych używa kodowania utf-8 oraz zawiera tekst, którego nie da się zakodować w latin-2 (np. tekst zawierający długi myślnik). Być może rozwiązanie, które za chwilę przedstawię nikomu się już do niczego nie przyda ale przynajmniej zostanie na pamiątkę dla przyszłych pokoleń.

Nie da się tego problemu tak po prostu obejść. Tzn. jeżeli tylko wykonywane zapytanie na bazie danych przy połączeniu w kodowaniu latin-2 zwraca dane, których nie da się w tym kodowaniu zakodować to każde jedno się po prostu wywali. Zatem jedynym rozwiązaniem tego problemu jest poprawienie tych znaków. Jednakże wyszukiwanie ich ręcznie może być bardzo czasochłonne.

Pierwsza rzecz, którą możemy zrobić to połączenie się psqlem i ustawienie odpowiedniego kodowania dla tego połączenia:

set client_encoding = latin2;

Teraz możemy próbować szukać w jakiej tabeli występuje dany znak. Wystarczy po prostu wykonać:

select * from tabela;

i jeżeli mamy szczęście to otrzymamy od razu komunikat:

BŁĄD: znak sekwencją bajtów 0xe2 0x80 0x9e kodowany w "UTF8" nie ma równoważnego w kodowaniu "LATIN2"

Pozostaje nam teraz zlokalizować wiersz i kolumnę, gdzie interesujący nas znak występuje. Mam na to dwie metody.


Pierwszy sposób

Pierwsza wykorzystuje fakt, że w komunikacie o błędzie występuje zapis szesnastkowy danego znaku. Możemy spróbować zatem go zlokalizować w taki oto sposób:

select id from tabela where encode(kolumna::bytea, 'hex') ilike '%e2809e%';

Zapytanie wykorzystuje postgresową funkcję encode, która potrafi zamienić tekst na reprezentację szesnastkową i w tej reprezentacji poszukujemy ciągu znaków zwróconego nam przez komunikat błędu. Pomijamy tylko 0x występujące w komunikacie. Metoda ta ma dwie wady:

  1. musimy znać kolumnę, w której dany znak może wystąpić (albo podać warunki na każdą kolumnę z użyciem or: ... where encode(kolumna1::bytea, 'hex') ilike '%..%' or encode(kolumna2::bytea, 'hex') ilike '%..%' or ..).
  2. komunikat o błędzie kodowania znaku zwraca nam informację tylko o pierwszym takim przypadku. Jeżeli jest ich więcej to będziemy poprawiać po jednym i czekać aż postgres zwróci nam informację o kolejnym.

Drugi sposób

Druga metoda znajduje wszystkie rekordy, które zawierają "błędne" znaki w tabeli. Niestety wykonanie go trwa znacznie dłużej.

select id
from tabela
where regexp_replace(encode(translate(kolumna, 'ęóąśłżźćńĘÓĄŚŁŻŹĆŃ', '')::bytea, 'hex'), '(.{2})', '\1 ', 'g') ~ '^[8-9a-f]| [8-9a-f]';

Jak już wspomniałem zapytanie wyłapie wszystkie rekordy w tabeli z "niepoprawnymi" znakami w podanej kolumnie. Zapytanie jest dość skomplikowane więc omówię je krok po kroku:

  1. zacznijmy od najbardziej zagnieżdżonego wywołania: translate(kolumna, 'ęóąśłżźćńĘÓĄŚŁŻŹĆŃ', '') Funkcja translate zamienia znaki występujące w jej drugim argumencie na znaki występujące w jej trzecim argumencie. Czyli w tym przypadku po prostu je usuwa. Robimy tak dlatego, że polskie znaczki są jedynymi dwubajtowymi znakami w kodowaniu utf-8, które posiadają swój odpowiednik w kodowaniu latin-2. Takie nas nie interesują. Chcemy wyłapać wszystkie wielobajtowe znaki, których nie ma w latin-2.
  2. encode(..::bytea, 'hex') - zamieniamy znaki na ich szesnastkową reprezentację. Każdy bajt jest teraz zapisany jako dwa znaki.
  3. regexp_replace(.., '.{2}', '\1 ', 'g') - zamieniamy każde dwa znaki jako x i spację. Po prostu rozdzielamy każdy bajt spacją.
  4. ~ '^[8-9a-f]| [8-9a-f]' - operator ~ sprawdza czy podany string odpowiada wyrażeniu regularnemu. Z kolei to wyrażenie sprawdza czy w ciągu znaków występuje 8, 9, a, b, c, d, e lub f, które jest albo na początku stringa albo jest poprzedzone spacją. Chodzi o to, że chcemy wyłapać czy istnieje bajt większy od 127 a taki będzie się zaczynał od tych znaków w reprezentacji szesnastkowej. Jeżeli istnieje to mamy nasz rekord.

Przy tym rozwiązaniu znów musimy testować sobie wszystkie tekstowe kolumny ale przynajmniej wyłapiemy od razu wszystkie rekordy. Możemy oczywiście napisać sobie zapytanie, które wszystkie niedozwolone znaki usunie lub zamieni na inne. Pozostawiam to już w kwestii czytelnika.