8 thoughts on “.

  1. Jeszcze był jakiś #suchar o tym jak Związek Sowiecki wykradł ostatnie 4kb kodu z amerykańskiej satelity.
    Okazało się ze to same )))))))))))))))))))))))))))

    Lubię to

  2. Cóż, prawie wszystko to, co Graham napisał o Lispie odnosi się również do Haskella. Może z tym tylko wyjątkiem, że Haskell nie powstał w latach 50-tych. W szczególności największą prawdą jest to, że poza cuchnącym bajorkiem C++, C# i Javy, jest wielki, wspnaniały świat. I prawdą jest też to, że programista z czasem zaczyna myśleć w swoim języku programowania. Co może być kłopotliwe; gdzieś czytałem kiedyś żale człowieka, który myślał z Haskellu, ale musiał pisać w C++. Naprawdę mu współczułem.

    Jedno, co mnie trochę niepokoi, to fakt, że Haskell nie ma makr. A w sumie to czasem mogłyby się przydać. Ale ostatecznie… co komu szkodzi napisać własny preprocesor dla dowolnego języka, albo w ogóle dowolny nowy język programowania? Czyżbym nadal był Blubem? :p

    Lubię to

  3. @Świętomir: No nieeee.. to nie tak. Trudno porównywać Haskella do Lispu a tymbardziej z pewnościa nie jest tak, że Grahamowe peany na cześć Lispu odnoszą się do Haskella.
    Zaraz wytłumaczę, na początek zaznaczam że moja znajomośc Haskella jest zdecydowanie mniejsza niż Lispu, więc otwarcie mówię: popraw mnie jeśli okaże się że nie mam racji.
    Poniżej masz zasadnicze sprawy które różnią oba języki, a które były dla sukcesu Grahama/Yahoostores istotne oraz cechy które Graham zachwalał
    1) Haskell zauważ jest czysto funkcyjny i kropka. Common Lisp — jest jaki chcesz: chcesz pisać funkcyjnie — z powodzeniem możesz, bywają czasem „side effects” ale to nie szkodzi; chcesz pisać obiektowo? Ależ proszę bardzo! jest CLOS który notabene jest lepszy od jakiejkolwiek obiektowości jaką widziałem (tak C++ i Java schowajcie się pod dywan). Upierasz się przy procedurach, no trudno, skoro musisz, będzie to koślawe, ale możesz!.
    2) Tu najbardziej jestem niepewny: w Lispie możesz online zmienić kod aplikacji bez jej restartu. Podpinasz się do VM lispu, rekompilujesz daną funkcję i po sprawie (ale jak mówię być może akurat to też osiągalne w Haskellu [choć nie wiem czy tak łatwo] — popraw mnie)
    3) Typizacja. Haskell zdaje sie jest statyczny (?). W Common Lispie fachowcy robią tak: piszą prototyp softu ignorują wogóle_ typy danych, jak program osiągnie fazę końcową i trzeba go zoptymalizować (tak! robi sie to tylko gdy wydajność tego wymaga 🙂 przedwczesna optymalizacja jest źródłem wszelkiego zła!) to wtedy można oznaczyć zmienne typami (w praktyce są to hinty dla kompilatora, które dają znac czego/jakiego typu należy sie spodziewać po danej zmiennej).
    4) Z tym sie wiąże kolejna sprawa CL ma bardzo zaawansowany optymalizator kodu i kompilator do kodu maszynowego. Więc jak juz soft osiągnie etap optymalizacji to można dać znów hinty kompilatorowi jak ma optymalizować kod. Ba! Świetne jest to, że tego typu optymalizacja nie musi odnosić się do całego kodu. Możesz kazać kompilatorowi optymalizować w jeden sposób jeden kawałek kodu, a drugi w inny sposób!
    5) Istotną cechą Common Lispu i całej rodziny lispów w ogólności jest to że dane są kodem. tzn. składnia jest tak minimalistyczna, że dane możesz traktować jak kod wyrazenie ‚(+ 3 4) jest listą ale tylko dlatego że jest quote’owane, jak potraktujesz je evalem, to się wykona, bo dane = kod.
    6) i tu dochodzimy do ostatniego Twojego akapitu – to nie tak, że do dowolnego języka możesz dodać preprocesor i będziesz miał lispowy system makr. W lispie makra maja tę jedyną i wielka siłę przede wszystkim dlatego właśnie, że dane są kodem i makra tak naprawdę definiują Ci język na nowo, makra są w stanie wygenerować Ci nowa funkcję i zmienić istniejący kod. W C/C++ itp makra to marny dodatek typu „text expansion” który wyłącznie operuje na ciągach znaków. W lispie nie dośc że operujesz na kodzie lispu to jeszcze w makrach możesz używać w pełni całego języka Lisp! No i @mt3o ma rację — większość lispu jest właśnie napisana w lispie — właśnie z powyższego powodu.

    Nie chcę w żadnym razie deprecjonować Haskella — też świetny język i ma wiele swoich mocnych stron (i nauczenie się go mimo wieku z 4 z przodu, jest wciąż na mojej liście to-do). Ale chciałem wyjaśnić po prostu parę spraw dla których Grahamowe pochwały Lispu jednak nie mogą się odnosić do Haskella 🙂

    Lubię to

  4. @sprae parser mój drogi to akurat pryszcz nad pryszcze. Bo cała składnia lispu to wyrażenia S-exp czyli coś w stylu „(a b c d e)” przy czm jak jest quotowane to traktowane jak ciag. i tyle. Twoj kolega zapewne napisał jakis prosty interpreter lispu (bo odmian jest mnóstwo) najpewniej w dodatku byla to bardziej odmiana scheme niz prawdziwego lispu.
    Tymczasem żeby napisać implementację Common Lispu.. ooo panie… ludzie nad tym latami pracują, żeby zrobić coś co jest porządne i zgodne ze standardem ANSI.

    Co do zaś kalkulatora… to tak jako ciekawostkę powiem. Ci co chodzili do liceum na pocz. lat 90 pamietaja pewnie taki popularny pakiet matematyczny Derive. Napisany był właśnie w Lispie. Jest też bardzo stary pakiet typu Algebra system do obliczeń symbolicznych o nazwie Macsyma. Teraz rozwijany pod nazwą Maxima. Istniał ZANIM jeszcze powstała słynna teraz Mathematica Wolframa. Niemniej jednak Maxima do dziś jest potężnym narzędziem które jest używane przez wiele osób, tym bardziej że darmowe 🙂

    Lubię to

  5. Niestety dopiero teraz przeczytałem komentarz Yen. Odpowiadam:

    No właśnie! Przewagą Haskella nad wszelkimi językami hybrydowymi jest właśnie to, że wymusza czysto funkcyjny kod. To znaczy, jak się uprzesz, to możesz napisać cały program w monadzie IO, w jednej funkcji i możesz mieć czystość kodu gdzieś. Będzie to koślawe, ale będzie działać. Możesz też programować obiektowo w Haskellu. Co prawda podejście Haskella do polimorfizmu jest trochę inne od tego znanego z C++/Javy. W szczególności nie ma klas (a więc i dziedziczenia) w takim sensie, jak w tamtych językach (ale możesz osiągnć podobne efekty w inny sposób). No i Twoje obiekty będą zawsze const, ale to tyle ograniczeń.

    Gdzie tu zaleta? Ano zaleta jest taka, że Haskell daje Ci potężną ochronę za określoną cenę. Nie pozwala na skróty, nie toleruje żadnej nieścisłości. Mówiono kiedyś o C++, że jak program w tym języku się skompiluje, to istnieje znaczne prawdopodobieństwo, że będzie działał poprawnie. W Haskellu jest to jeszcze bardziej prawdziwe. I zysk w postaci optymalizacji nie jest jedynym, ani nawet najważniejszym. Najważnijesze jest to, że kompilator stale patrzy Ci na ręcę, i pilnuje żebyś nie zrobił czegoś głupiego.

    Haskell nie jest homoikoniczny, o ile mi wiadomo. Chociaż jeżeli spojrzysz na XMonad, zobaczysz, że plik konfiguracyjny tego programu jest w istocie haskellowym modułem kompilowanymi i linkowanym z XMonad w czasie uruchomienia. Nie interesowałem się, jak to jest dokładnie zrealizowane, ale prawdopodobnie możliwe jest skompilowanie i dynamiczne zlinkowanie modułu z programem w czasie jego działania.

    Co do modyfikowania działającego codu sensu stricto, prawdopodobnie nie jest to szczególnie potrzebne. Haskell po prostu przyjmuje inną taktykę. Na potęgę używa się funkcji wyższego rzędu. Funkcja, a nawet konstruktor, przyjmujący funkcję jako argument jest na porządku dziennym. Efekt? Jeżeli potrzebujesz, aby jakiś kawałek kodu był modyfikowany w czasie działania, to po prostu robisz z niego funkcję wyższego rzędu i tym sposobem możesz „wstawić w puste miejsce” cokolwiek zechcesz. 😉

    Tak, Haskell jest statycznie typowany. I osobiście uważam to za ogrmną zaletę. Chociaż doceniam siłę dynamicznego typowania, to często bywa ona denerwująca (na codzień programuję w Pythonie, więc wiem, co mówię). Rzecz w tym, że w dynamicznie typowanym języku masz potencjalnie dużo więcej obsługi błędów na głowie. Przykład z zycia wzięty. Haskell ma typ Rational, który reprezentuje nieobliczony iloraz dwóch wartości numerycznych. Pozwala Ci w praktyce pracować na ułamkach bez obawy o błąd zaokrąglenia, ponieważ moduł wie, jak przekształcać ułamki, więc ostateczne dzielenie może być wykonane dopiero wtedy, kiedy naprawdę potrzebujesz wartości dziesiętnej (czyli w praktyce najczęściej nigdy). Chciałem analogiczny typ zaimplementować w Pythonie. I zaraz zaczęło się zastanawianie: a co, jeżeli użytkownik wrzuci mi do ułamka string? Przecież muszę to sprawdzić i rzucić wyjątkiem w razie czego. Ile zbędnego kodu! Błędów kompilacji nie trzeba obsługiwać i tu tkwi siła statycznego typowania.
    Haskell również kompiluje się do kodu maszynowego. I pomimo iż ma na głowie leniwe wartościowanie, zarządzanie pamięcią itd., przeważnie nie ustępuje wydajnością C. To również nie byłoby możliwe gdyby nie statyczne typowanie i brak efektów ubocznych.
    Składnia Haskella również jest bardzo prosta, a mimo tego niezwykle ekspresyjna. Może nie aż tak prosta, jak składnia Lispu, ale z pewnością dużo prostsza niż jakiegokolwiek mainstreamowego języka. Niewiele jest rzeczy piękniejszych niż:

    f x = filter (< x) [1..100]

    Toż to czysta matematyka. 🙂

    Nie twierdzę oczywiście, że wskazane przez Ciebie różnice nie mają znaczenia. Po prostu języki te różni filozofia i metoda rozwiązywania tych samych problemów. Oba są skuteczne, w wielu wypadkach to kwestia smaku, czy preferujemy to, czy tamto rozwiązanie. Jeżeli chodzi o moje preferencje, poczucie estetyki (to wbrew pozorom bardzo ważne!), Haskell jest po prostu strzałem w dziesiątkę. Próbowałem kiedyś podejść do Scheme, ale jakoś mnie nie przekonał. Nawiasem mówiąc istnieje tutorial Parseca, w którym pisze się interpreter uproszczonej wersji Scheme. 😉

    Lubię to

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Wyloguj / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Wyloguj / Zmień )

Connecting to %s