Některé zajímavé konstrukce
                         -=-=-=-=-=-=-=-=-=-=-=-=-=-=-

               Within a computer, natural language is unnatural.

          Tak tady  bych Vám rád načrtl  možnosti  Lispu na několika  málo
      příkladech. Lispové knihovny se od těch v C hodně lišší. Jak už jsem
      ukázal v případě  quicksortu, jejich  použití je mnohem  obratnější.
      I vlastní  knihovny  mohou být  chytřejší.  Lisp umí dobře  pracovat
      s funkcemi s proměným počtem parametrů, umožňuje dělat funkce, které
      akceptují víc typů.  Takže  například  knihovní  funkce  member může
      fungovat jak na listy, tak třeba na pole, stromy a další typy. Navíc
      Lisp umožňuje  přidávat z knihoven  další jazykove  konstrukce. Jako
      je už zmíněná konstrukce cond, nebo objekty. Programování v Lispu je
      vlastně pouze volání různých funkcí.

          Existují funkce pro práci z různými typy. Standardní  schemovská
      knihovna  podporuje  například  následující: pole, asociované  listy
      (prvky  seznamu jsou přístupné  pomocí  klíčů.  Například  struktura
      udržující  jměna  proměných je asociovaný list - pro každé  jméno má
      hodnotu),  colections  (to je cosi  jako  struktura,  tedy  obsahuje
      hodnoty   přístupné  přes  klíče,  ale  navíc  podporuje   například
      pročítání hodnotu po hodnotě a další), dynamic,  hashovací  tabulky,
      chapter  ordering  (typ,  který  udržuje  data  ve  stejném  formátu
      jako  kapitoly a podkapitoly v knize),  object  (podpora  pro  OOP),
      parameter list (slouží k předávání parametrů funkci), fronty, fronty
      s prioritou, rekordy , relační databáze, RB stromy a struktury.

          Jak  vidíte, je z čeho  vybírat.  Nebudu tu  všechno  popisovat.
      Jenom bych rád na několika příkladech ukázal, jak to funguje.

          Jednotlivé  typy ve scheme  jsou  většinou  listy, ze  speciální
      hlavičkou.  (podobně  jako  fhunkce  používají  lambda).   Například
      objekty používají #object

                                        OOP

          Objektově   orientované  programování  je  docela  nový  přístup
      k věci. Do  některých  jazyků  byl  dodatečně  přidán  (třeba do C).
      Většinou  to  potřebovalo  dost  změn a stejně se  nejedná o objekty
      v pravém slova smyslu. Pouze o jakousi  náhražku  objektů. Ve scheme
      nic takového  nutné  nebylo. Zde se vytváří  objekty  knihovna. Těch
      existuje  několik.  Nejznámější je CLOS pro  Common  Lisp. Já tu mám
      implementaci jménem yasos (Yet Another  Scheme Object  System) a tak
      popíšu tu.

          Objekt v Lispovém  pojetí je seřazený  asociovaný  seznam metod.
      Metody do objektu se  přidávají  pomocí  make-method! a ruší  pomocí
      unmake-metod!.  Objekty  mohou  také  dědit  metody  od  libovolného
      množství předků. Vzniká následovně:

      ==> (define bagr (make-object))

        bagr


          Za  make-object  může  následovat   seznam  předchůdců.   Funkce
      make-object  sama  vygeneruje kód  objektu.  Pro  zajímavost  vypadá
      následovně:

      #("object" (lambda (generic-method)
              (let ((method-def (assq generic-method method-list)))
                                        (if method-def
                                        (cdr method-def)
#f))
               ) (lambda (generic-method method)
                   (set! method-list (cons (cons generic-method method)
                         method-list))
                   method ) (lambda (generic-method)
                              (set! method-list (object:removeq generic-method
                                                 method-list))
                              #t ) (lambda ()
                                     method-list ))


          Ale to nás naštěstí nemusí zajímat.

          Možná  teď v tom  máte  trochu  zmatek. V OOP  se  přece  napřed
      vytvářejí třídy a potom teprve objekty. Tady mluvíme hned objektech.
      To je pravda. Pokud chci použít  vytváření přes třídy,  vytvořím pro
      trídu objekt a přidám konstruktora. To je normální  metoda. Většinou
      se ve scheme  jmenuje  instantiate. K tomu ale musím  vysvětlit, jak
      fungují metody ve scheme.

          Volání  cílových metod je jednoduché.  Zavoláte  prostě  (metoda
      objekt  parametry).  Scheme ale metody  nezná a volá  funkce. Ty ale
      nelze definovat pro každý typ zvlášť.

          To se řeší tak, že se vytvoří  funkce, která zjistí, jaký objekt
      má jako parametr a podle toho zpustí tu správnou metodu. K vytváření
      takove funkce slouží (make-generic-metod)

      ==>      (define instantiate (make-generic-method))

      instantiate


          Funkce instantiate potom vypadá takto:


      ==> (write instantiate)
      (lambda (obj . operands)
        (if (object? obj)
          (let ((object-method ((vector-ref obj 1) generic-method))) (if
               object-method (apply object-method (cons obj operands))
               (slib:error "Method not supported: " obj)))

          (apply exception-procedure (cons obj operands))) )
      ()


          Nyní  můžeme  napsat  metodu  instantiate a přiřadit  ji každému
      objektu,  který  je  třída.  To ale  můžeme  zautomatizovat a napsat
      si následující pomůcku:

     (define (make-instance-object . ancestors)
       (define self (apply make-object
                           (map (lambda (obj) (instantiate obj)) ancestors)))
       (make-method! self instantiate (lambda (self) self))
       self)


          Ta už zařídí  prázdného  konstruktura každé  instanci. Nyní máme
      třídy,  instance,  objekty,  metody a dědičnost a tak už máme téměr.
      kompletní OOP.  Nejdůležitější  věc,  kterou jsem tu přezkočil  jsou
      proměné pro obejkt.  Objekt ale má svůj  lokílní  binding a tak může
      mít  privítní  proměné.  Sice  postup  je  poněkud  komplikovanější,
      než u čistě objektových  jazyků, ale nemá narozdíl od C++ či pascalu
      žádné větší potíže. Navíc je tento postup velmi rozšiřitelný a další
      vymoženosti (jako privátní metody a public proměné) jde velmi snadno
      přidat. (ve standardní implementaci samozřejmě existují)


                                     Autoload


          Jak jsem říkal, lisp je založen na knihovnách. Není ale nejlepší
      nápad  je po startu  překladače  všechny  nahrát  do  paměti.  Jedna
      metoda jak toto řešit je funkce, co daný soubor přihraje  (require),
      ale  je  možné  to i zautomatizovat.  K tomu  slouží  autoload.  Ten
      funguje tak, že pokud chcete mít nějakou  funkci  dostupnou,  prostě
      napíšete defaultoload, jméno funkce a jméno modulu, co se má dohrát.
      On prostě vytvoří  funkci, která sama daný modul dohraje a zavolá tu
      správnou. Tím se zruší a vše funguje  normálně. Díky tomu je v Lispu
      možné psát cosi jako hlavičkové soubory.


                                      Nápověda


          Hodně lispů celkem elegantně  přidává  nápovědu. Do lambda listu
      ještě přidají místo pro text. Potom dodělají  funkci help která daný
      text zobrazí a máte zdarma celkem šikovný systém pro dokumentování.

                                       Advice


          Další  často  používanou  metodou  pro  rozšiřování  programů je
      advice.  Funguje to podobně jako dědičnost v OOP. Pokud  potřebujete
      nějakou  funkci  rozšiřit,  ptostě  přidáte  advice,  což je funkce,
      která se  může  volad  před,  nebo  po  volání  dané  funkce.  Tímto
      způsobem byl například do Emacs přidán  Emacsspeak. Emacs je editor.
      Emacsspeak je podpora pro slepé. Umí číst to co je na obrazovce, ale
      velmi intelignetně. Pokud například posunete kurzor o slovo dobrava,
      přečte dané slovo. Toho je docíleno tak, že existuje  funkce  "posuň
      kurzor o slovo doprava" a Emacsspeak pouze přidá advici, která slovo
      přečte.  Nemusí tedy dělat  vůbec  žádné zásahy do zdrojáků a přitom
      může velmi intelignetně číst, to co je na obrazovce.


          A to bude asi všechno. Není to zdaleka  kompletní vyčet možností
      lispu, spíš ukázka toho, co v něm lze vytvořit.


            výheň