Funkce a lambda calculus
                           -=-=-=-=-=-=-=-=-=-=-=-=-=

                        ((lambda (foo) (bar foo)) (baz))

          Už o Lispu víme  hodně. Ale to nejdůležitější  pořád ne. Neumíme
      vytvářed  žádné  funkce. Je možné  provédst  jednoduchý  experiment.
      Napsat  (write  write).  Uhádnete  co se stane?  No já vám  napovím.
      Proměná write má hodnotu. Tou je jak víte funkce,  která vypisuje na
      obrazovku. Tedy:

      ==> (write write)
      (lambda (obj . port)
        (#_write obj (if (null? port)
                (current-output-port)
                (car port))) )
      ()

          vypíše  opravdu  zajímavou  věc. Jak už možná  tušíte,  jedná se
      o kód funkce write.  Existuje  dohoda, že listy začínající  symbolem
      lambda  jsou  funkce.  Jejich  vyhodnocování v případě,  že jsou  na
      prvním  místě  seznamu  probíhá  následovně:  vyhodnotí  se  všechny
      další prvky seznamu. Potom se provede  binding  lokálních  proměných
      - vytvoří se lokální  seznam  jmen  pro  proměné a nastaví se  podle
      seznamu  následujícím těsně za lambda. V našem případě (obj . port).
      Tento  seznam  říká, že první  parametr je obj. Tedy prvnímu
      parametru přiřadí jméno obj. Pak následuje . a port. To je konstrukce
      pro  proměný  počet  parametrů.  Pokud  eval  narazí  na .,  všechny
      případné další parametry pospojuje do listu a dá jim jedno jméno.

          Potom následuje  seznam  výrazů, které se vyhodnotí.  Nakonec se
      lokální  kontext pro proměné  zruší a hodnota  posledního  výrazu se
      vrátí. Můžeme tedy vesele programovat:

      ==> ((lambda (a) (+ 1 2)(+ a 1)) 5)

      6

          Tady se vytvářím tzv. anonymní  funkci.  Místo abych ji přiřadil
      nějaké  jméno,  rovnou ji napíšu  do volání. Má  jeden  parametr  a,
      který se nastaví na 5. Potom se začne  provádět tělo funkce. (+ 1 2)
      se vyhodnotí na 3 a výsledek se rovnou  zapomene. Potom následuje (+
      a 1). a se  vyhodnotí  na 5 a výsledek  je  tedy 6. Protože to už je
      poslední výraz v seznamu, provádění funkce se ukončí a vrátí se 6.

          No a to je  celé.  Teď  už až  na  drobné  detaily  Lisp  umíte.
      Ted se můžu pokusit vysvětlit  včem práve zpočívá  genialita  Lispu.
      Zatím jsme se bavili o samých low level věcech. Přesto ale je pomocí
      nich možné vyvořit  cokoliv. Je to právě tím, že program i data jsou
      to samé. Jakýkoliv program je totiž List. Díky tomu je možné vyvářet
      funkce za běhu.  Proto lisp není  procedurální  jazyk. Je tedy možné
      například  napsat funkci pro vytváření  třídy. Ta vyvoří  funkce pro
      jednotlivé  metody. Ale nedá tam přímo kód té metody, ale kód, který
      podle vstupního  parametru  (instance  objektu) zjistí, jakou metodu
      má zavolat a tu zavolá.  Díky tomu je pak možné  stejnojmené  metody
      použít i pro  jiné  třídy  aniž by došlo ke kolizi.  Podobné  takové
      příklady uvedu později.

          Aby syntaxe byla lidštější, má define rozšíření, kde můžete psát
      funkce, aniž byste vypisovali lambdu:

      ==> (define (inc a) (+ a 1))

      inc
      ==> (write inc)
      (lambda (a)
        (+ a 1) )
      ()
      ==> (inc 1)

      2


                       Řídící konstrukce v lispu a makra
                      -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

      Any programming language is at its best before it is implemented and
                                     used.

          Další  geniálním  nápadem  lispu je to, že vůbec nemá  speciální
      řídící konstrukce. Místo toho má makra. Například if v lispu funguje
      následovně:

      ==> (if (< 1 2) 'mensi 'vetsi)

      mensi

          if  je  cosi  jako  funkce.  Před  jeho  voláním  se  ale  listy
      nevyhodnocují,  jako  u  funkce,  ale  předají  se  parametry  ještě
      nevyhodnocené. if potom sám  zavolá  eval na první  parametr.  Podle
      toho  jestli se  vyhodnotí do true  (#t ve scheme)  vyhodnotí  druhý
      parametry a pokud ne, tak třetí.  První  parametr je tedy  podmínka,
      druhý then větev a třetí else.

          K vytváření maker slouží funkce  defmacro. Celý princip je velmi
      podobný  funkcím. Místo symbolu  lambda se používá  defmacro.  Makra
      jsou ale mnohem  mocnější, než ty v C, protože jsou zabudovány až do
      interpretru a tedy znají syntax  vlastního  jazyka. Jsou také mnohem
      robusnější.  Téměř  vše, o čem jsme se tu bavili,  lze implementovat
      jako makra. Jako makra jde napsat i mnoho  dalších  věcí - debugger,
      smyčky apod.  Nebudu to zde rozvádět,  protože  psaní  maker není už
      úplně triviální záležitost.

          Důležité  ale je to, že  Lisp  vlastně  není  jenom  interpretr.
      Ale je to jakýsi interpretr  intepretru, protože většina  konstrukcí
      je v něm  napsána. To dává  lidem  možnost,  aby  sami  modifikovali
      jazyk  tak, jak  chtějí. Už samotná  konstrukce  defmacro je napsána
      v normální knihovně a tak implementována bez dalších konstrukcí.


            výheň