Příklad
-=-=-=-=-
Real computer scientists only write specs for languages that might
run on future hardware. Nobody trusts them to write specs for
anything homo sapiens will ever be able to fit on a single planet.
Lisp je velmi výkoný a úsporný programovací jazyk. Jako příklad
jsem si vybral quick sort. Každý asi znáte tento algoritmus.
Implementovat ho v C není tak velká legrace. V Lispu to je snadné.
Protože Lisp má mnohem mocnější pojetí funkcí a maker, můžete velmi
elegantně využívat knihovních funkcí, které toho umí opravdu hodně.
(define (partition compare l1)
(cond
((null? l1) '())
((compare (car l1)) (cons (car l1) (partition compare (cdr l1))))
(else (partition compare (cdr l1)))))
(define (quicksort l1)
(cond
((null? l1) '())
(else (let ((pivot (car l1)))
(append (append (quicksort (partition (lambda (x) (< x pivot))
l1))
(partition (lambda (x) (= x pivot)) l1))
(quicksort (partition (lambda (x) (> x pivot)) l1)))))))
Jak to funguje? Začneme od funkce partition. Ta rozdějule seznam
l1 podle funkce compare na dvě části. Napřed otestuje jestni už není
nahodou hotový. K tomu slouží makro cond. Jedná se o chytřejší if.
Bere své parametry jeden po druhém. Každý parametr je list. Jako
první v listu očekává podmínku. Pokud se podmínka vyhodnotí do #t,
provede tělo za podmínkou a zkončí. Jinak pokračuje na další
podmínku. Na konci můře být volitebně else větev. Jedná se tedy
o něco mezi switch a case.
První podmínka je (null? l1). Funkce null? vrací #t pokud jeho
parametr je prázdný seznam. Takže pokud je parametr prázdný seznam,
funkce zkončí.
Jinak porovná první prvek seznamu l1, pokud je menší, rekurzivně
se zavolá na zbytek seznamu a prvek přihodí na začátek (pomocí
funkce cons, která ze svých parametrů vytvoří cons).
Pokud je ale prvek větší, zahodí ho a rekruzivne se zavolá
na zbytek.
Funkce quicksort potom používá této funkce. Na začátku opět
ošetří, jestli není seznam nulový. Pokud není, vybere pivota ze
začátku seznamu a provede rozdělení. Partitiion potom volá z nově
vytvořenou funkcí, která vybere ty prvky, které potřebuje. Quicksort
se zavolá rekurzivně na obě větve a vše je hotovo.
Kód není zrovna optimální. Chtěl jsem na něm ukázat co nejvíc
konstrukcí, ale když ho srovnáte se srovnatelně funkčním quicksortem
v C, Lisp na délku kódu rozhodně vede.
I použítí je jednodušší:
(quicksort '(1 3 2 6 5 4 0))
=> (0 1 2 3 4 5 6)
ekvivalent v C:
#include <stdio.h>
#include <stdlib.h>
int nums[] =
{1, 3, 2, 6, 5, 4, 0};
int
compar (const void *a, const void *b)
{
return (*(int *) a - *(int *) b);
}
void
main (void)
{
int i;
qsort (nums, sizeof (nums) / sizeof (int), sizeof (int), compar);
for (i = 0; i < sizeof (nums) / sizeof (int); i++)
printf ("%i ", nums[i]);
printf ("\n");
}
výheň