domingo, 27 de abril de 2008

Kanamit?

Paradigma funcional O Érico Andrei e o Ricardo Bánffy fizeram uma pegadinha de 1º de abril muito interessante, chamada Kanamit.

Na brincadeira, é feita a suposição de um framework para aplicações web em Lisp.

Mas sabe que a ideia não é tão estúpida assim? Ela me deixou cheio de ideias malignas…

É claro, não é um framework, mas vamos bricar de usar Lisp em aplicações web em ambiente GNU/Linux!

Primeiro baixe e instale o LIGHTTPD fly light. Não vou entrar em detalhes de instalação.

Habilite o uso de CGI – ainda preciso ver como habilitar FastCGI – e configure cgi.assign em lighttpd.conf com as seguintes entradas mínimas:
cgi.assign = (
".el" => "/usr/bin/clisp",
".fas" => "/usr/bin/clisp",
".lisp" => "/usr/bin/clisp",
".ss" => "/usr/bin/guile"
)


Depois a gente brinca com Smalltalk.

Acrescente também index.lisp à variável index-file.names.

Tendo reiniciado o LIGHTTPD, podemos ir ao script index.lisp, que deve estar no diretório raiz do LIGHTTPD, configurado pela variável server.document-root.
; index.lisp

(defun floor-div (a b)
(multiple-value-bind
(resp)
(floor (/ a b))
resp))

(let (
(content-type "text/html")
(title "Teste de Lisp")
(date "")
(century ""))

(multiple-value-bind
(S M H d m y)
(get-decoded-time)
(setq date
(format nil "~2,'0d/~d/~4,'0d" d m y))
(setq century
(format nil "~@r" (+ (floor-div (- y 1) 100) 1))))

(format t "Content-type: ~A~%~%" content-type)
(format t "<html>~%")
(format t "<head>~%")
(format t "<title>~A</title>~%" title)
(format t "</head>~%")
(format t "<body>~%")
(format t "<h1 align=\"center\">~A</h1>~%" title)
(format t "<p>Ol&aacute; Mundo!</p>~%")
(format t "<p>Data: ~A</p>~%" date)
(format t "<p>S&eacute;culo: ~A</p>~%" century)
(format t "</body>~%")
(format t "</html>~%"))


Agora acesse http://localhost/index.lisp.

Ok! Ok! Até aqui é só CGI… mas vou dar uma olhada com mais calma em FastCGI e quem sabe desenvolver um rascunho de framework só por curtição. =)

É claro, preferiria fazer em Smalltalk, mas alguém já fez primeiro. Deem uma olhadinha na Superfície Reflexiva.

[]'s
Cacilhas

PS: Artigo publicado nas Reflexões de Monte Gasppa e Giulia C..

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

terça-feira, 22 de abril de 2008

Por que paradigma funcional é mais lento do que imperativo?

haskell Alguém procurou no Google por que paradigma funcional é mais lento do que imperativo e caiu na página do Walter.

É uma pergunta interessante e a resposta não é muito difícil.

Se você programar recursivamente usando paradigma imperativo, vai ficar ainda mais lento do que funcional.

No paradigma funcional, recursividade é um recurso muito usado, enquanto que no paradigma imperativo é comum o uso de ciclos de repetição condicional – loops – para resolver os problemas por meio de reiteração – apesar de corrente, o uso do estrangeirismo iteração não é correto.

[update 2008-04-23]Eduardo Willians avisou que o dicionário Houaiss data a palavra «iteração» de 1858. Vide comentários abaixo.[/update]


Algoritmos reiterativos são conhecidamente mais eficientes do que algoritmos recursivos. Mesmo a recursão linear, sabidamente rápida, é ligeiramente mais lenta do que seu equivalente reiterativo.

Linguagens funcionais são otimizadas para trabalhar com recursividade, portanto mais eficientes em recursões do que linguagens imperativas, no entanto tal otimização não compensa a diferença de desempenho entre algoritmos recursivo e reiterativo.

No entanto o paradigma funcional não é necessariamente mais lento do que o imperativo para todos os casos.

Em procedimentos que exigem muita álgebra ou inteligência artificial, linguagens funcionais são mais eficientes, especialmente quando se faz a substituição dos algoritmos recursivos por funções fechadas.

Funções fechadas são difíceis de serem definidas, mas extremamente eficientes, muito mais do que reiterações. Combinadas com a otimização para recursividade, o uso de funções fechadas pode tornar o paradigma funcional mais eficiente do que o imperativo para casos específicos.

[]'s
Cacilhas, La Batalema

sábado, 19 de abril de 2008

Peculiaridades do GNU Smalltalk

VisualWorks Visual Works é uma ótima ferramenta para desenvolvimento de grandes sistemas em Smalltalk, no entanto suas limitações na versão gratuita são extremamente incômodas.

Há algumas boas alternativas ao Visual Works, como Squeak e GNU Smalltalk.

Como sou fã do Projeto GNU, escolhi como substituto GNU Smalltalk.

Mas GNU Smalltalk também tem lá seus inconvenientes, todos contornáveis com a criação de uma nova imagem personalizada, o que pode ser feito na linha de comando ou com a ajuda da ferramenta gráfica Blox.

Também podemos resolver esses «inconvenientes» no próprio código. Por exemplo, cadê a potência (#**)?

[update 2008-06-12]O trouxa aqui não sabia que os números em Smalltalk respondem à mensagem raisedTo:. =P[/update]


Vamos calcular potência de dois em GNU Smalltalk:
#!/bin/sh
"exec" "gst" "-f" "$0" "$@"

Number extend [
** val [
| aux |

aux := 1.
1 to: aux do: [ :i |
aux := aux * self
].
^aux.
]
].


0 to: 10 do: [ :i |
Transcript
show: i printString;
tab;
show: (2 ** i) printString;
cr.
].


Claro, esta não é uma solução definitiva para potência, apenas um quebra-galho.

A mensagem extend estende os recursos de uma classe acrescentando novos métodos, no caso #** (potência).

Vamos agora ao cálculo de números primos…

O método #at:ifAbsent: de Dictionary, quando retorna o valor por defeito, não o retorna diretamente, mas passa a ele a mensagem value, que quase nenhuma classe trata.

Então precisamos estender Object para tratar a mensagem:
#!/bin/sh
"exec" "gst" "-f" "$0" "$@"

Object extend [
value [
^self
]
].

count := 0.
max := 5000.
primeList := Dictionary new.

primeList at: 1 put: false.

2 to: max do: [ :i |
(primeList at: i ifAbsent: true) ifTrue: [
Transcript show: i printString; tab.
count := count + 1.
(i * 2) to: max by: i do: [ :j |
primeList at: j put: false
]
]
].

Transcript
cr;
show: 'Quantidade de primos: ', count printString;
cr.


Conforme for encontrando outras peculiaridades do GNU Smalltalk, vou postando aqui.

[]'s
Cacilhas, La Batalema

sexta-feira, 18 de abril de 2008

Io

Smalltalk Depois de cinquenta e três dias afastado da rede mundial, estou de volta, podendo novamente postar artigos.

Para marcar esta volta, quero falar de uma novíssima linguagem de programação que, apesar ainda estar saindo do forno – não sei sua idade, mas deve ter pouco mais de um ano –, pode vir a se tornar uma escolha viável: Io.

Io é uma linguagem de programação pequena e prototipada. Seus conceitos são inpirados em outras linguagens de programação, como Smalltalk, Self, Lisp, Lua e outras.

É uma linguagem de código aberto – licença BSD –, a máquina virtual é pequena – por volta de 10KB – e roda atualmente em quatro plataformas: Unix-like, Windows, Symbian e Syllable – antigo AtheOS.

Possui uma sintaxe muito semelhante à de Smalltalk e um forte conceito de orientação a objetos.

Em Io, em vez de atributos, propriedades, métodos e variáveis, temos slots. Slot consiste no armazenamento de um objeto dentro de outro, ou seja, cada objeto possui slots contendo outros objetos.

Todas linhas de código são mensagens interceptadas pelo objeto Lobby: a primeira «palavra» é interpretada como o nome de um slot de Lobby. Caso o slot não exista, é gerada uma exceção.

Caso exista, o objetos residente naquele slot é retornado e o resto da mensagem é passada para ele, e assim sucessivamente.

Se o objeto num dos slots for um método, ele será executado e seu retorno será usado para tratar o restante da mensagem.

A atribuição de valor a um slot é feita por =, caso o slot não exista, será gerada uma exceção. Para a criação – e inicialização – de um novo slot, é usado :=.

Não há classes propriamente didas: a «instanciação» é feita por meio de protótipos, ou seja, clonagem de um objeto matriz.

Vamos a um exemplo…

Vamos criar um protótipo Person, que contenha nome, sobrenome e retorne o nome completo:
Person := Object clone
Person firstname := ""
Person lastname := ""
Person birth := Date
Person fullname := method("#{firstname} #{lastname}" interpolate)
Person asString = method(fullname .. ": " .. birth asString("%Y-%m-%d"))


Para «instanciar» um objeto de Person também usamos clone:
cacilhas := Person clone
cacilhas firstname = "Rodrigo"
cacilhas lastname = "Cacilhas"
cacilhas birth = Date fromString("1975-11-20", "%Y-%m-%d")


Ao ser executado:
cacilhas fullname println


Será exibido Rodrigo Cacilhas.
cacilhas println


Agora é exibido Rodrigo Cacilhas: 1975-11-20.

Para obter a data atual:
Date now println


Também é possível obter uma representação numérica da data usando asNumber, que no caso retorna a data em segundos:
Date now asNumber println


Outros slots válidos de Date now são: year (ano), month (mês), day (dia), hour (hora), minute (minuto) e second (segundo).

Pegando apontadores do Google:
SGML
xml := URL with("http://www.google.com/search?q=io+language") fetch asXML
links := xml elementsWithName("a") map(attributes at("href"))


Espero que tenham achado a linguagem tão interessante quanto eu achei e que ela alcance um nível de maturidade que permita sua aplicação extensiva.

[]'s
Cacilhas, La Batalema