sexta-feira, 25 de abril de 2008

Common Lisp

Paradigma funcional Uma das linguagens de programação mais interessantes que já conheci é Lisp.

Antes de começar, gostaria de pedir um pouco de tolerância e boa vontade do leitor, pois não sei programar em Lisp, só conheço o básico, portanto vou me arrastar pelo artigo tentando dizer algo útil… =/

Lisp é uma linguagem de programação funcional muito usada em projetos de IA. Há também algumas aplicações conhecidas feitas em Lisp, como Emacs e AutoCAD.

Antes de ser padronizada como Common Lisp, havia muitos dialetos.

Se você possui um sistema GNU/Linux a mão, podemos começar a experimentar:
bash$ clisp
  i i i i i i i       ooooo    o        ooooooo   ooooo   ooooo
  I I I I I I I      8     8   8           8     8     o  8    8
  I  \ `+' /  I      8         8           8     8        8    8
   \  `-+-'  /       8         8           8      ooooo   8oooo
    `-__|__-'        8         8           8           8  8
        |            8     o   8           8     o     8  8
  ------+------       ooooo    8oooooo  ooo8ooo   ooooo   8

Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
Copyright (c) Bruno Haible, Sam Steingold 1999-2000
Copyright (c) Sam Steingold, Bruno Haible 2001-2006

[1]> 


Os comandos em Lisp são chamados forms e representados sempre entre parêntesis. Por exemplo:
[1]> (print "Olá Mundo!")

"Olá Mundo!"
"Olá Mundo!"
[2]> 


A primeira impressão é o resultado do form print, a segundo é o retorno.

Para criar uma variável podemos usar setq:
[2]> (setq foo 12)
12
[3]> foo
12
[4]> 


Outra forma é com let, que faz atamento, mas então a variável só existe no escopo:
[4]> (let ((bar 15)) (print foo) (print bar))

12
15
15
[5]> 


O último 15 é o retorno de let, que é o mesmo retorno do último form do escopo – (print bar).

Agora veja:
[5]> foo
12
[6]> bar


*** - EVAL: variable BAR has no value
The following restarts are available:
USE-VALUE      :R1      You may input a value to be used instead of BAR.
STORE-VALUE    :R2      You may input a new value for BAR.
ABORT          :R3      ABORT
Break 1 [7]> abort
[8]> 


Há alguns símbolos especiais, como t (verdadeiro), nil (nulo) e as palavras-chave, iniciadas por ::
[8]> :teste-de-lisp
:TESTE-DE-LISP
[9]> 


Lisp possui uma estrutura de par chamada cons:
[9]> (cons 3 4)
(3 . 4)
[10]> 


Listas em Lisp são conses aninhados:
[10]> (cons 1 (cons 2 (cons 3 (cons 4 nil))))
(1 2 3 4)
[11]> 


Um apelido para isso é:
[11]> (list 1 2 3 4)
(1 2 3 4)
[12]> 


O form car retorna o primeiro elemento do cons e o form cdr retorna o segundo:
[12]> (car (list 1 2 3 4))
1
[13]> (cdr (list 1 2 3 4))
(2 3 4)
[14]>


Só alguns forms – nem de longe tudo:
  • push – coloca um elemento no começo de uma lista, retornando a lista;
  • pop – remove o primeiro elemento de uma lista, retornando-o;
  • defun – define e retorna uma função;
  • format – imprime e/ou retorna uma string;
  • if, case, cond e whenforms condicionais;
  • block, prog e progn – bloco;
  • loop – ciclo (loop) incondicional;
  • dolist – equivale mais ou menos ao for de Python;
  • lambdalambda!!!
  • sort – ordenação;
  • =, eq e equal – igualdade;
  • find – procura elemento numa lista.


Uma coisa curiosa de Lisp é sua sintaxe extremamente funcional:
[14]> (if (= foo 12) "sim" "não")
"sim"
[15]> 


Repare em (= foo 12)! Primeiro a função a ser executada – igualdade –, depois os parâmetros.

Para terminar de forma interessante esse artigo, segue o crivo de Aristóstenes:
(let ((c 0) (noprime (list)) (index 1) (max 5000))
  (loop
    (setq index (+ index 1))
    (if (not (find index noprime))
      (progn
        (format t "~D~4@T" index)
        (setq c (+ c 1))
        (let* ((j (* index 2)))
          (loop
            (pushnew j noprime)
            (when (>= j max) (return))
            (setq j (+ j index))))))
    (when (>= index max) (return)))
  (format t "~%Contagem de primos: ~D~%" c))


[update 2008-06-13]Código sugerido pelo Pedro:
(defun primos (max)
  (let ((c 0) (noprime ()))
    (loop
      for index-1 from 2 to max
      unless (member index-1 noprime)
      do (format t "~D~4@T" index-1)
      (incf c)
      (loop
        for index-2 from (* index-1 2) to max by index-1
        do (pushnew index-2 noprime)))
        (format t "~%Contagem de primos: ~D~%" c)))


Valeu Pedro![/update]


Em outro momento explicarei comando a comando. Por ora, espero que achem Common Lisp tão interessante quanto achei. Para mais informações, vejam em meu del.icio.us, principalmente esse tutorial.

[]'s
Cacilhas, La Batalema
blog comments powered by Disqus