tca@diale.org

RSS

[Valid RSS]

diale.org

Fotografias com efeito Lomo

2010/02/08-14:20:01

Fotografia original.
Fotografia original.
Transformação Lomo.
Transformação Lomo.
Fotografia original.
Fotografia original.
Transformação Lomo.
Transformação Lomo.
Fotografia original.
Fotografia original.
Transformação Lomo.
Transformação Lomo.

Tenho uma Lomo (uma LC-A) já há alguns 9 anos. Gosto dos efeitos descontraídos que se obtêm quando se usam as regras

  1. Take your camera everywhere you go
  2. Use it any time – day and night
  3. Lomography is not an interference in your life, but part of it
  4. Try the shot from the hip
  5. Approach the objects of your lomographic desire as close as possible
  6. Don’t think (william firebrace)
  7. Be fast
  8. You don’t have to know beforehand what you captured on film
  9. Afterwards either 10. Don't worry about any rules

mas tinha pena em não obter o mesmo efeito usando um máquina digital. Ora, para variar, a função em Emacs Lisp usando o ImageMagick que produz esse efeito é este

(defun lomo (source-dir img-file)
  (let ((img-file-lomo (concat source-dir "lomo-" img-file )))
    (shell-command 
     (format "cp %s %s"
             (concat source-dir img-file)
             (concat source-dir (concat "lomo-"img-file))))
    (shell-command 
     (format "convert -resize 1024x768 %s %s" 
           img-file-lomo img-file-lomo))
  (shell-command 
   (format "convert -unsharp 1 %s %s"
           img-file-lomo img-file-lomo))
  (shell-command 
   (format "cp %s %s" 
           img-file-lomo (concat img-file-lomo "-resized")))
  (shell-command 
   (format "convert -contrast -contrast %s %s"
           img-file-lomo  img-file-lomo))
  (shell-command 
    (format "convert -modulate 100,150 %s %s"
           img-file-lomo img-file-lomo))
  (shell-command 
   (format "composite -compose overlay %s %s %s"
           (concat source-dir "mask.png")
           img-file-lomo img-file-lomo))
  (shell-command 
   (format "composite -compose multiply %s-resized %s %s"
           img-file-lomo
           img-file-lomo
           img-file-lomo))
  (shell-command 
   (format "rm %s-resized" img-file-lomo))))

baseado neste.

Etiquetas: Lomo, Lisp, Emacs, ImageMagick


Script em ELisp para fotos

2010/02/07-08:50:39

Já há muito tempo que andava para fazer este script em ELisp para gerar uma lista de imagens em html.

(let ((img-file-list  (directory-files source-dir () "\\.\\(jpg\\|JPG\\|png\\|gif\\)$")))
  (while img-file-list 
    (shell-command (format "convert -geometry %sx%s %s %s" 200 200 (concat source-dir (car img-file-list))
                           (concat source-dir "thumb." (car img-file-list))))
    (insert "<literal>")
    (insert "<a href=\""(concat "./photos/" (car img-file-list))"\">"
     "<img class=\"photo-album\" src=\"" (concat "./photos/" "thumb." (car img-file-list))  "\"></a>\n")
    (insert "</literal>")
    (setq img-file-list (cdr img-file-list))))

Claro que pode ser bastante melhorado, mas para começo não está mal.

Etiquetas: Lisp, Emacs, fotografias, html


Pipes law

2010/02/07-00:19:00

Os modelos de modelação de tráfego mais simples são os chamados modelos follow-the-leader. latex2png equation

O mais simples corresponde a tomar o valor da aceleração do i-ésimo carro com sendo proporcional à diferença de velocidades do carro seguinte e a sua latex2png equation Este modelo não inclui o tempo de reacção do condutor, para o incluir basta introduzir um tempo de reacção latex2png equation que reflecte o tempo de reacção, finito, de cada condutor. Obtém-se assim um modelo de estímulo-resposta (Pipes law) dado pelas equações latex2png equation A quantidade latex2png equation mede a sensibilidade ao estímulo. Estas equações pertencem à classe de equações diferenciais ordinária com atraso cujas soluções para latex2png equation se tornam instáveis. Prova-se que (Chandler et al., 1958) as variações das velocidades individuais de cada carro são amplificadas quandolatex2png equation, dando origem a ondas de pára-arranca e a acidentes.

Etiquetas: tráfego, modelos, matemática, follow-the-leader, Pipes law


Trabalhos práticos de física

2010/02/05-14:40:08

Ref: H. Amorim Ferreira, Dr.Sc., "Trabalhos práticos de física", Livraria Sá da Costa, 1931, 2ª ed.

Etiquetas: física, gotas


Gotas

2010/02/05-10:37:48

As equações que modelam a forma de gotas numa superfície (sinal -) ou suspensas (sinal +) são:

latex2png equation

As figuras mostram as soluções que se obtém para os perfis de gotas sobre uma superfície hidrófoba e gotas suspensas.

Gotas sobre uma superfície.
Gotas sobre uma superfície.
Gotas suspensas.
Gotas suspensas.

Código em LaTeX para a equações

\begin{eqnarray*}
\frac{d \varphi}{d s}&=& \mp  2 z-\frac{\sin \varphi}{r}\\
\frac{d r}{d s}&=& \cos \varphi\\
\frac{d z}{d s}&=& \sin \varphi
\end{eqnarray*}

Código em GNU/Octave

clf
hold on

z=-1
x0=[.001 z 0]
t=linspace (0,pi*.9,100);
y=lsode ("fu",x0,t);
plot(y(:,1),y(:,2))
plot(-y(:,1),y(:,2))

z=-1
x0=[.001 z 0]
t=linspace (0,pi/2+.1,100);
y=lsode ("fl",x0,t);
plot(y(:,1),y(:,2))
plot(-y(:,1),y(:,2))

axis("square")
grid on
xlabel("r")
ylabel("z")
print -dsvg "drop.svg"
function xdot=fl(x, t)
  xdot(1)=cos(x(3));
  xdot(2)=-sin(x(3));
  xdot(3)=-2*x(2)-sin(x(3))/x(1);
endfunction
function xdot=fu(x, t)
  xdot(1)=cos(x(3));
  xdot(2)=-sin(x(3));
  xdot(3)=2*x(2)-sin(x(3))/x(1);
endfunction

Etiquetas: física, matemática, gotas, equações, LaTeX


Bach + catmap

2010/02/03-13:46:23

1
1
2
2
10
10
20
20
30
30
40
40
50
50
60
60
70
70
80
80
90
90
100
100
110
110
120
120
130
130
140
140
150
150
151
151

Animação das sucessivas iterações do catmap aplicada a uma imagem de Bach (50x50). O primeiro retorno ocorre na iteração 151.
151 iterações
151 iterações

Etiquetas: JSBach, catmap


Monte Carlo Pi

2010/02/03-10:58:54

Distribuição aleatória de pontos.
Distribuição aleatória de pontos.

Uma das formas mais engraçadas de calcular uma aproximação ao número PI é a de considerar um círculo de raio um inscrito no quadrado de lado dois; gerar um conjunto de pontos aleatoriamente com coordenadas dentro do quadrado, e se o ponto estiver dentro do círculo é contado, no caso de cair fora não se conta. O número de pontos que cai dentro do círculo a dividir pelo número total de pontos vezes quatro é aproximadamente igual a 3.1415926... Como se pode verificar no gráfico seguinte da quantidade referida em função do número de pontos; a linhas vermelha é o valor 3.1415926...

Convergência para o valor de Pi.
Convergência para o valor de Pi.

O código seguinte em GNU/Octave faz todo o trabalho:

clf;
hold on
axis square
u=[0:.01:2*pi];
plot(cos(u),sin(u),'r-')

n=500;

x=2*rand(n,2)-1;
px=[];
j=0;
for i=1:n
  if sumsq(x(i,:))<1
    plot(x(i,1),x(i,2),'o')
    j=j+1;
    px(j)=4*j/i;
  else
  endif;
endfor;

[j i]
print -dpng "circPI.png"
clf;
hold on;
plot(px,'-')
plot([1:length(px)],pi*ones(1,length(px)),'r-')
print -dpng "circPIx.png"

Etiquetas: Pi, Monte Carlo, matemática


Pepper map

2010/02/03-10:20:55

121 iterações pela aplicação "cat map" de Arnold
121 iterações pela aplicação "cat map" de Arnold
A figura mostra 121 iterações pela aplicação "cat map" de Arnold, necessárias para que o primeiro retorno ocorra, de um pimento.

É necessário ter alguma paciência para as ver todas...

A aplicação em GNU/Octave é esta:

function y=catmap(x,n)
  [nx ny]=size(x);
  for i=1:nx
    for j=1:ny
      y(i,j)=x(1+mod(i+j,n),1+mod(i+2*j,n));
    endfor;
  endfor;
endfunction;

Sempre desejei fazer uma figura destas!

P. S.

Já está na Wikipedia em: en.wikipedia.org/wiki/Arnold%27s_cat_map

Etiquetas: cat map, Arnold, matemática


Power tower

2010/02/02-11:31:25

Hiper-superfícies de nível das sucessivas potências de z
Hiper-superfícies de nível das sucessivas potências de z
A imagem mostra as hiper-superfícies de nível das funções zz, zzz e zzzz, respectivamente dispostas por linhas; cada coluna mostra a parte real, imaginária e valor absoluto de cada uma. Note-se que z = x + i y.

Código em GNU/Octave

clf;
n=3,
m=3;
[x y]=meshgrid([-2:.05:2],[-2:.05:2]);
z=x+1i*y; 
w=z.^z;
subplot(n,m,1)
contour(x,y,real(w),-2:.05:2) 
axis square

subplot(n,m,2) 
contour(x,y,imag(w),-2:.05:2)
axis square

subplot(n,m,3)
contour(x,y,abs(w),-2:.05:2)
axis square

subplot(n,m,4)
contour(x,y,real(w.^z),-2:.05:2) 
axis square

subplot(n,m,5)
contour(x,y,imag(w.^z),-2:.05:2)
axis square

subplot(n,m,6)
contour(x,y,abs(w.^z),-2:.05:2)
axis square

subplot(n,m,7)
contour(x,y,real(w.^w),-2:.05:2) 
axis square

subplot(n,m,8)
contour(x,y,imag(w.^w),-2:.05:2)
axis square

subplot(n,m,9)
contour(x,y,abs(w.^w),-2:.05:2)
axis square

Etiquetas: matemática, Lambert, power tower


i9 = inove

2010/02/02-11:31:18

Nunca fui um apaixonado pela tecnologia, sempre gostei mais do que estava dentro de um gadget do que do gadget propriamente dito. Isto faz de mim um hacker 1 e não um techie2. Não tenho um iPhone mas gostava de ter um Openmoko pelas capacidades e possibilidades que encerra em si mesmo. Num artigo publicado na sua crónica semanal do Expresso (30/Jan/2010), Nuno Crato (NC) revela: "sou um teckie". Na verdade deveria querer dizer techie.

Se é verdade que não se espera que os alunos aprendam mais só porque o professor gosta de gadgets tecnológicos, é meio caminho andado, para que aprendam, que o professor goste de saber como funcionam esses gadgets. E é esta pequena diferença que faz com que a introdução de tecnologia no funcionamento das aulas resulte, e o ser hacker em vez de teckie faz muita diferença.

Talvez seja esta a diferença entre o sucesso das mesmas experiências de ensino activo feitas por físicos como Mazur e aquelas desenvolvidas por Steenhuis, o SABER como as coisas funcionam. É mais razoável duvidar da universalidade dos matemáticos do que da matemática. Ser hacker ou techie, eis a questão?

1. "A person who enjoys exploring the details of programmable systems and stretching their capabilities, as opposed to most users, who prefer to learn only the minimum necessary." (http://catb.org/jargon/)

2. "A person who displays a great, sometimes even obsessive, interest in technology, high-tech devices, and particularly computers." (http://en.wikipedia.org/wiki/Techie)

Etiquetas: Notícias, tecnologia, Jornal Expresso, Nuno Crato, hacker, techie


As raízes de Lisp

2010/02/02-11:31:09

(revisão da tradução do artigo de Paul Graham de http://www.paulgraham.com/rootsoflisp.html para português e agora em HTML)

Em 1960 John McCarthy publicou um artigo espantoso no qual fez para a programação o mesmo que Euclides fez para a geometria (Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I, Communications of the ACM 3:4, April 1960, pp. 184-195). Mostrou como construir, dado uma mão cheia de operadores simples e uma notação para funções, uma linguagem de programação completa. Denominou-a de Lisp, abreviatura de List Processing, porque a ideia chave era usar uma estrutura simples de dados chamada lista para o código e para os dados propriamente ditos.

O que McCarthy descobriu não foi só aquilo que se tornou um marco para a história dos computadores, e que vale por si só, mas um modelo para o qual convergem, no nosso tempo, as linguagens de programação. Parece-me a mim que existem apenas dois tipos de modelos realmente escorreitos e consistentes: o modelo do C e o de Lisp. Estes dois modelos parecem estar bem alto com baixios pantanosos entre si. Com o aumento da capacidade dos computadores as linguagens de programação que têm surgido convergem para o modelo de Lisp. A receita mais popular para construir uma nova linguagem de programação nos últimos 20 anos consiste em considerar o modelo de C e adicionar partes do modelo de Lisp, tais como runtime typing e garbage collection.

Neste artigo tentarei explicar de uma maneira simples o que McCarthy descobriu. O objectivo não é só o de aprender um resultado teórico importante que alguém descobriu à quarenta anos atrás, mas mostrar para onde tendem as linguagens de programação. A coisa pouco usual do Lisp — de facto, a qualidade que o define — é que se escreve a si mesmo. Para se entender o que McCarthy quer dizer com isto, vamos repetir os seus passos, traduzindo a sua notação matemática em código Common Lisp.

Sete operadores primitivos

Para começar, definimos o que se entende por expressão. Uma expressão é, alternativamente, um átomo, que é uma sequência de letras (por exemplo: foo), ou uma lista de zero ou mais expressões, separadas por espaços em branco e enquadradas por parêntesis. De seguida mostram-se várias expressões:

foo
()
(foo)
(foo bar)
(a b (c) d)
A última expressão é uma lista de quatro elementos, o terceiro dos quais é uma lista de um elemento.

Em aritmética a expressão 1+1 tem o valor 2. Uma expressão válida de Lisp também tem um valor. Se uma expressão e tem o valor v dizemos que e return v. O passo seguinte é definir que tipo de expressões podem existir e que tipo de valor têm.

Se uma expressão é uma lista, chamamos ao primeiro elemento da lista operador, e os restantes elementos argumentos. Vamos, no que se segue, definir sete operadores primitivos (no sentido de axiomas): quote, atom, eq, car, cdr, cons, e cond.

quote

(quote x ) retorna x. Para uma leitura mais simples abreviamos (quote x) por 'x.

> (quote a)
a
> 'a
a
> (quote (a b c))
(a b c)

atom

(atom x) retorna o átomo t se o valor de x é um átomo ou a lista vazia (). Em Lisp convenciona-se usar o átomo t como representando o valor lógico verdade, e a lista vazia como o valor lógico falso.

> (atom 'a)
t
> (atom '(a b c)
()
> (atom '())
t
Agora que temos um operador cujo argumento é avaliado podemos mostrar para que é que quote serve. Através de quoting (Nota do tradutor: não vou traduzir quote por citação de modo a que não se perca o sentido em Inglês da frase) uma lista protegemo-la de ser avaliada. Uma lista unquoted como argumento de um operador como por exemplo atom é tratada como código:
> (atom (atom ' a))
> t
enquanto uma lista quoted é tratada como uma mera lista, neste caso uma lista de dois elementos
> (atom '(atom 'a))
()

Isto corresponde à maneira de usar citações em Inglês (Nota do tradutor: ver o que se passa em PT). Cambridge é uma cidade de Massachusetts que contém cerca de 90.000 habitantes. "Cambridge" é uma palavra de nove letras.

quote pode parecer um conceito estranho, não há muitas línguas com coisa semelhante. Está intimamente ligado a uma das características distintivas de Lisp: o código e os dados são feitos de uma mesma estrutura, e o operador quote é uma maneira de distinguir os dois.

eq

(eq x y) retorna t se os valores de x e y

são o mesmo átomo ou ambos uma lista vazia, e () caso contrário.

> (eq 'a 'a)
t
> (eq 'a 'b)
()
> (eq '() '())
t

car

(car x) espera que o valor de x seja uma lista, e

retorna o seu primeiro elemento.

> (car '(a b c))
a

cdr

(cdr x ) espera que o valor de x seja uma lista, e

retorna o resto da lista a seguir do primeiro elemento.

> (cdr '(a b c))
(b c)

cons

(cons x y) espera que o valor de y seja uma lista, e

retorna uma lista contendo o valor de x seguido dos elementos valor de y.

> (cons 'a '(b c))
(a b c)
> (cons 'a (cons 'b (cons 'c '())))
(a b c)
> (car (cons 'a '(b c)))
a
> (cdr (cons 'a '(b c)))
(b c)

cond

(cond (p1 e1) ... (pn en)) e avaliado da seguinte forma. As expressões p são avaliadas até que uma retorna t. Quando uma é encontrada, o valor correspondente da expressão e é retornado como o valor total da expressão cond.

> (cond ((eq 'a 'b) 'first)
        ((atom 'a) 'second))
second

Os argumentos de cinco dos sete operadores primitivos anteriores são avaliados quando uma expressão com esse operador é avaliado. Chamaremos a esses operadores funções.

Denotando funções

De seguida definimos a notação para a descrição de funções.

Uma função é representada por ((lambda (p1 ... pn) e) a1 ... an), onde p1 ... pn são átomos (chamados parâmetros) e e é uma expressão. Uma expressão cujo primeiro elemento é uma expressão

((lambda (p1 ... pn) e) a1... an)
é chamada de função e o seu valor é calculado da seguinte forma. Cada expressão ai é avaliada. Depois e é avaliada. Durante a avaliação de e, o valor de qualquer ocorrência de qualquer um dos pi é o valor do ai correspondente na mais recente chamada da função.
> ((lambda (x) (cons x '(b))) 'a)
(a b)
> ((lambda (x y) (cons x (cdr y))) 'z '(a b c))
(z b c)

Se uma expressão tem como primeiro elemento um átomo f que não é um dos operadores primitivos (f a1 ... an) e o valor de f é uma função (lambda (p1 ... pn)e) então o valor da expressão é o valor de ((lambda( p1 ... pn)e) a1 ... an).

Por outras palavras, os parâmetros podem ser usados com expressões assim como argumentos

> ((lambda (f) (f '(b c)))
   '(lambda (x) (cons 'a x)))

Existe outra notação para funções que permite que uma função se chame a si própria, permitindo assim de uma forma conveniente definir funções recursivas (definidas por recorrência) (não é necessário definir uma nova notação para isto. Poderia-mos definir funções recursivas com nossa notação através de do construtor Y. McCarthy poderia não conhecer o Y construtor na altura em que escreveu o artigo; de qualquer modo, a notação label é de leitura mais simples).

A notação label f (lambda (p1 ... pn) e) denota a função que se comporta como lambda (p1 ... pn) e), com a propriedade adicional que uma ocorrência de f dentro de e avaliará a expressões label, como se f fosse um parâmetro da função.

Suponhamos que queremos construir uma função subst(x y z), que toma uma expressão x, um átomo y e uma lista z, e retorna uma lista tipo z onde cada instância y (em qualquer nível) é substituída em z por x.

> (subst 'm ' b '(a b (a b c) d))
(a m (a m c) d)

Podemos escrever esta função como

(label subst (lambda (x y z)
               (cond ((atom z)
                      (cond (eq z y) x)
                            ('t z))
                     ('t (cons (subst x y (car z))
                               (subst x y (cdr z)))))))

Vamos abreviar f (label f (lambda (p1 ... pn)e)) por (defun f(p1 ... pn e)) e logo ficamos com

(defun subst (x y z)
  (cond ((atom z)
         (cond ((eq z y) x)
               ('t z)))
        ('t (cons (subst x y (car z))
                  (subst x y (cdr z))))))

Acidentalmente, podemos ver que uma condição definida por omissão numa expressão cond. Uma condição cujo primeiro elemento é 't é sempre executada. Assim (cond( x y)('t z)) é equivalente aquilo que se poderia escrever numa outra linguagem com sintaxe if x then y else z.

Algumas funções

Agora que temos uma maneira de expressar funções, podemos definir novas em termos dos nossos sete operadores primitivos. Em primeiro lugar é conveniente introduzir algumas abreviaturas. Vamos usar cxr, como uma sequência de a ou d, correspondendo a composição de car e cdr. Por exemplo (cadr e) é uma abreviatura de (car (cdr e)), que retorna o segundo elemento de e.

> (cadr '((a b) (c d) e))
(c d)
> (caddr '((a b) (c d) e))
e
> (cdar '((a b) (c d) e))
(b)

Vamos também usar (list e1 ... en) para significar (cons e1 (cons e2 (...(cons en'())))).

> (cons 'a (cons 'b (cons 'c '())))
(a b c)
> ( list 'a 'b 'c)
(a b c)

Vamos definir novas funções. Alterei os nomes das funções que se seguem introduzindo um ponto o fim. Isto distingue as funções primitivas daquelas definidas à custa delas, e também evita confusões com aquelas que já existem em Commnon Lisp.

null

(null. x) testa se o seu argumento é uma lista vazia.

(defun null. (x)
  (eq x '()))

> (null. 'a)
()
> (null. '())
t

and

(and. x y) retorna t se ambos os argumentos o são, () caso contrário.

(defun and. (x y)
  (cond (x (cond (y't) ('t '())))
        ('t '())))

> (and. (atom 'a) (eq 'a 'a))
t
>  (and. (atom 'a) (eq 'a 'b))
()

not

(not. x) retorna t se o seu argumento é (), e () se o seu argumento é t.

(defun not. (x)
  (cond (x '())
        ('t 't)))

> (not. (eq 'a 'a))
()
>  (not. (eq 'a 'b))
t

append

(append. x y) toma duas listas e retorna a sua concatenação.

(defun append. (x y)
  (cond ((null. x) y)
        ('t (cons (car x) (append. (cdr x) y)))))

> (append.'(a b) '(c d))
(a b c d)
> (append. '() '(c d))
(c d)

pair

(pair. x y) toma duas listas com o mesmo comprimento e retorna uma lista de listas de dois elementos, com pares de formados com elementos de cada uma das listas iniciais.

(defun pair. (x y)
  (cond ((and. (null. x) (null. y)) '())
        ((and. (not. (atom x)) (not. (atom y)))
         (cons (list (car x) (car y))
               (pair. (cdr x) (cdr y))))))

> (pair. '(x y z) '(a b c))
((x a) (y b) (z c))

assoc

(assoc. x y) toma um átomo x e uma lista y da forma criada por pair., e retorna o segundo elemento da primeira lista de y

que contém x como primeiro elemento.

(defun assoc. (x y)
  (cond ((eq (caar y) x) (cadar y))
        ('t (assoc. x (cdr y)))))

> (assoc. 'x '((x a) (y b)))
a
> (assoc. 'x '((x new) (x a) (y b)))
new

A surpresa

Assim conseguimos definir funções que concatenam listas, substituem uma expressão por outra, etc. Talvez seja apenas uma notação elegante, e depois? Agora chega a surpresa. Podemos também escrever uma função que funciona como um interpretador da nossa linguagem: uma função que tem como argumento uma expressão de Lisp, retornando o seu valor. Aqui está ela:

(defun eval. (e a)
  (cond
    ((atom e) (assoc. e a))
    ((atom (car e))
     (cond
       ((eq (car e) 'quote) (cadr e))
       ((eq (car e) 'atom)  (atom   (eval. (cadr e) a)))
       ((eq (car e) 'eq)    (eq     (eval. (cadr e) a)
                                    (eval. (caddr e) a)))
       ((eq (car e) ' car)  (car    (eval. (cadr e) a)))
       ((eq (car e) 'cdr)   (cdr    (eval. (cadr e) a)))
       ((eq (car e) 'cons)  (cons   (eval. (cadr e) a)
                                    (eval. (caddr e) a)))
       ((eq (car e) 'cond)  (evcon. (cdr e) a))
       ('t (eval. (cons (assoc. (car e) a)
                         (cdr e))
                  a))))
   ((eq (caar e) 'label)
    (eval. (cons (caddar e) (cdr e))
           (cons (list (cadar e) (car e)) a)))
   ((eq (caar e) 'lambda)
    (eval. (caddar e)
           (append. (pair. (cadar e) (evlis. (cdr e) a))
                    a)))))

(defun evcon. (c a)
  (cond ((eval. (caar c) a)
         (eval. (cadar c) a))
        ('t (evcon. (cdr c) a))))

(defun evlis. (m a)
  (cond ((null. m) '())
        ('t (cons (eval. (car m) a)
            (evlis. (cdr m) a)))))

A definição de eval. é bastante maior do que as definições que vimos anteriormente. Vamos estuda-la em mais detalhe e por partes.

A função tem dois argumentos: e, a expressão a ser avaliada, e a, uma lista que representa os valores que os átomos que aparecem como parâmetros das chamadas das funções. Esta última lista é chamada de ambiente, e é da forma da listas criadas por pair. e assoc..

A parte principal da função eval. é a expressão cond. que tem quatro condições (clausulas). A avaliação de uma expressão depende de qual é usada. A primeira clausula trata de átomos. Se e é um átomo, procuramos o seu valor no ambiente:

> (eval. 'x '((x a) (y b)))
a

A segunda clausula de eval. é um outro cond que trata de expressões da forma (a ...), onde a é um átomo. Estas incluem todos os tipos de operadores primitivos, e há uma clausula para cada um deles.

> (eval. '(eq 'a 'a) '())
t
> (eval. '(cons x '(b c))
         '((x a ) (y b)))
(a b c)

Todos eles (excepto quote) chamam eval. para determinar o valor dos seus argumentos.

As duas últimas clausulas são mais complicadas. Para avaliar uma expressão cond chamamos uma função subsidiária evcon., que percorre as clausulas de uma forma recursiva, procurando o primeiro elemento que retorna t. Quando o encontra tal clausula retorna o valor do segundo elemento.

> (eval. '(cond ((atom x) 'atom)
                 ('t 'list))
         '((x '(a b))))
list

A parte final da segunda clausula de eval. trata das chamadas das funções que são passadas como parâmetros. Funciona substituindo o átomo pelos seu valor (que deverá ser uma expressão lambda ou label)) avaliando o resultado da expressão. Assim

(eval. '(f '(b c))
       '((f lambda (x) (cons 'a x))))
\end{verbatim}
passa a ser
\begin{verbatim}
(eval. '((lambda (x) (cons 'a x)) '(b c))
       '((f (lambda (x) (cons 'a x)))))
que retorna (a b c).

As duas últimas clausulas de eval. tratam de chamadas de funções para as quais o primeiro elemento da lista é uma expressão lambda ou label. Uma função label é avaliada empurrando o nome da função e a própria função para o ambiente, e depois chamando eval. numa expressão onde a expressão lambda interior é substituída pela expressão label. Isto é,

(eval. '((label firstatom (lambda (x)
                            (cond ((atom x) x)
                                  ('t (firstatom (car x))))))
         y)
       '((y ((a b) (c d)))))
fica
(eval. '((lambda (x)
           (cond ((atom x) x)
                 ('t (firstatom (car x)))))
         y)
        '((firstatom
           (label firstatom (lambda (x)
                            (cond ((atom x) x)
                                  ('t (firstatom (car x)))))))
          (y ((a b) (c d)))))

que no fim retorna a.

Finalmente, uma expressão da forma ((lambda (p1 ... pn) e) a_1 ... a_n), é avaliada chamando em primeiro lugar evlis. de modo a obter uma lista de valores ( v_1 ... v_n) dos argumentos (a_1 ... a_n), avaliando e com (p1 v1) ... (pn vn) appended ao ambiente. Assim

(eval. '((lambda (x y) (cons x (cdr y)))
         'a
         '(b c d))
       '())
fica
(eval. '(cons x (cdr y))
       '((x a) (y (b c d))))
que no fim retorna (a c d).

Aftermath

Agora que percebemos como é que eval funciona, voltemos atrás para perceber qual é o seu significado. O que aqui temos é um modelo muito elegante para computação. Usando apenas quote, atom, car, cdr, cons e cond, podemos definir a função eval., que implementa a nossa linguagem de programação, usando-a depois para construir qualquer outra função que queiramos.

Como é claro, na altura já existiam modelos de computação — o mais notável exemplo sendo as máquinas de Turing. Mas os programas das máquinas de Turing não são muito edificantes de se ler. Se queremos uma linguagem para descrever algoritmos precisamos de algo mais abstracto, este foi um dos objectivos de McCarthy ao definir Lisp.

A linguagem definida em 1960 tinha muitas omissões. Não tinhas side-effects, nem execução sequencial (que apenas é útil com o anterior), sem números (é possível fazer cálculos de aritmética no Lisp de 1960 de McCarthy, usando, por exemplo, uma lista de n átomos para representar um número n) e dynamic scope. Todas estas limitações podem ser remediadas, surpreendentemente, com um pouco de código adicional. Isto mesmo foi mostrado por Steele e Sussman num famoso artigo intitulado "The Art of the Interpreter" (Guy Lewis Steele, Jr. and Gerald Jay Sussman, "The Art of the Interpreter, or the Modularity Complex (Part Zero, One and Two)", MIT AI Lab Memo 453, May 1978.

O entendimento do eval de McCarthy não é só perceber um patamar da história das linguagens. Estas ideias são ainda hoje parte do núcleo semântico do Lisp. Não é tanto o que McCarthy desenhou ou o que descobriu. Não é uma linguagem intrinsecamente para a IA ou para qualquer outra tarefa. É aquilo que obtemos quando tentamos axiomatizar a computação.

Com o passar do tempo, a linguagem média de programação (a linguagem usada pelo programador médio) tem-se aproximado do Lisp. Assim ao perceber eval estamos a perceber o que poderá ser o modelo principal de computação do futuro.

Etiquetas: Lisp, tradução, Paul Graham


A linguagem como um virus

2010/02/02-11:24:45

Aqui e aqui tratei de parte deste tópico.

O que é esta entidade estranha, a linguagem, e de onde é que veio? O que é ninguém o diz, que evoluiu apenas, de modo a incorporar as propriedades daquilo a que chamamos de linguagem. Coisa atribuída anteriormente, e por engano, ao cérebro. De onde veio? Qual a sua origem? Não interessa porque depois do seu aparecimento o mundo das linguagens evoluiu espontaneamente, através da evolução natural, processada fora do cérebro humano. Tornou-se, por isto, na coisa mais bem adaptada às pessoas; tal qual parasitas e hospedeiros, presas e predadores, num ciclo familiar de co-evolução; ou então vírus, usando uma analogia mais exacta. Mas ninguém acreditaria, ou proporia, que o sistema visual de um insecto ou mamífero se desenvolveria espontaneamente fora de qualquer um deles, por uma mutação rápida, agarrando-se depois a um hospedeiro, providenciando as capacidades visuais de moscas ou ratos.

Etiquetas: linguagem, natureza, Chomsky


Literate programming

2010/02/02-11:24:45

Tenho andado a ler o artigo de D. Knuth intitulado Literate programming. A ideia principal consiste na percepção de que o acto de construir um programa de computador e a construção da documentação são duas coisas indissociáveis; Knuth denominou a relação entre o programa de computador e a documentação de WEB.

O termo WEB foi escolhido porque, diz Knuth, era a única palavra em inglês com três letras que ainda não tinha sido usada para designar algo relacionado com computadores. Pode parecer estranho nos tempos que correm porque web é hoje a palavra que mais gente relaciona com computadores mas em 1980 (?-confirmar data) não havia ainda sombra de que a WWW alguma vez existisse.

A ideia subjacente a toda a construção do WEB system é a mudança de paradigma do acto de programar; em vez de imaginar que a principal tarefa inerente ao acto de programar é produzir um conjunto de instruções para serem executadas por um computador, passamos a explicar a um ser humano aquilo que queremos que um computador faça. Isto é conseguido através da construção de uma obra literária que incluirá num só sítio a documentação e as instruções a serem executadas por um computador.

O argumento de plausibilidade do sistema WEB de Knuth consiste em mostrar em como o conceito de programação estruturada levou os programadores a escreverem bons e melhores programas, fáceis de ler, de explicar e manter durante longos períodos de tempo, mas que não é inteiramente satisfatório; claro que se programa para um computador, mas a transmissão do conhecimento que um programa em si mesmo encerra é mais útil a outro ser humano do que propriamente para um computador e neste sentido uma obra literária talvez seja a melhor forma de transmissão de conhecimento entre humanos. Será? Knuth compara o programador a um ensaísta cujo estilo e excelência na sua exposição permitem a introdução no texto dos nomes e significado das variáveis usadas no programa de forma a que seja compreensível para um outro ser humano usando uma cuidada mistura de métodos formais e informais que se reforçam entre si.

O acto de programar é uma actividade muito pessoal, cada programador tem um estilo próprio e o resultado depende muito do autor. Cada autor escreve um programa da forma que acha que deve ser escrito.

A abordagem de Knuth consiste em tornar a relação entre o código e a documentação numa dualidade. De um mesmo texto, em texto WEB, o utilizador poderá extrair dois conteúdos: a primeira linha de processamento consiste no weaving the web que produz um documento que descreve o programa de uma forma clara e facilitando a sua manutenção; a segunda corresponde ao tangling the web, e produz o código-máquina do programa. O código e a sua documentação derivam assim de uma mesma fonte (source), garantindo a sua consistência.

Knuth afirma mesmo que o termo Literate programming contém alguma maldade. Durante os anos 70 todos os programadores foram forçados a escrever programas de uma forma estruturada, obrigando-se a reescrever os programas moralmente repreensíveis que não estivessem formatados na moral vigente; de modo a que a culpa controlasse os ímpetos menos estruturados. O termo "programação literária" tem exactamente o mesmo objectivo, introduzir uma moral irrepreensível no acto da escrita de programas de computador; certamente ninguém quererá escrever um programa de computador aliterado.

Etiquetas: Linguagem de programação, web, lisp, C, Knuth


Sumatório: imperativo vs funcional

2010/02/02-11:24:45

Duas formas de fazer a mesma coisa em Emacs Lisp, a primeira de uma forma imperativa, a segunda funcional; implementam a soma de um vector.

A primeira: forma imperativa

(defun sum (x)
  "Sum of elements of X."
  (let ((i 0) (aux 0))
    (while (< i (length x))
      (setq aux (+ aux (nth i x))
            i (1+ i)))
    aux))

A segunda: forma funcional

(defun sum (x)
  "Sum of elements of X."
  (cond (x
         (+ (car x) (sum (cdr x))))
        (t 0)))

Mais bonita, esta última!

Etiquetas: Emacs, Lisp, matemática, programação funcional, programação imperativa, programação


Revenge of the nerds

2010/02/02-11:24:45

Em 2002 Paul Graham escreveu um artigo intitulado "Revenge of the Nerds" que, entre outras coisas, fala das vantagens do uso de Lisp e o que o torna diferente das outras linguagens de programação. O que me levou até este artigo foi aquilo de que se trata no apêndice, i.e., sobre o poder de uma linguagem de programação.

As an illustration of what I mean about the relative power of programming languages, consider the following problem. We want to write a function that generates accumulators— a function that takes a number n, and returns a function that takes another number i and returns n incremented by i. (That's incremented by, not plus. An accumulator has to accumulate.)

Em Common Lisp a função que faz isto é dada por

(defun foo (n)
  (lambda (i)     
    (incf n i))) 
Para ver como funciona põe-se
> (setq a (foo 3))
#<FUNCTION :LAMBDA (I) (INCF N I)>

> (funcall a 1)
4

Fui ver então se a mesma função foo, definida anteriormente, funciona em Emacs Lisp. Depois de (funcall a 1) o resultado é este:

  Debugger entered--Lisp error: (void-variable n)
  (+ n i)
  (setq n (+ n i))
  (incf n i)
  (lambda (i) (incf n i))(1)
  funcall((lambda (i) (incf n i)) 1)
  eval((funcall a 1))
  eval-last-sexp-1(nil)
  eval-last-sexp(nil)
  call-interactively(eval-last-sexp

Aparentemente a variável n é considerada como local na definição de foo, mas isto não faz sentido nenhum. É um bug acidental ou propositado do dialecto de Lisp que corre no Emacs?

Email enviado para a mailing list do Emacs. Novidades aqui, mais tarde.

Já recebi a resposta da mailing list. Aqui está ela:

Should not the function foo in Common Lisp work with Emacs Lisp?

(defun foo (n)
  (lambda (i)     
    (incf n i))) 

No, that won't work because emacs has no lexical scoping and that code is a closure. See the elisp manual:

,----[ (info "(elisp)Extent") ]
|    To illustrate this, the function below, `make-add', returns a
| function that purports to add N to its own argument M.  This would work
| in Common Lisp, but it does not do the job in Emacs Lisp, because after
| the call to `make-add' exits, the variable `n' is no longer bound to
| the actual argument 2.
| 
|      (defun make-add (n)
|          (function (lambda (m) (+ n m))))  ; Return a function.
|           => make-add
|      (fset 'add2 (make-add 2))  ; Define function `add2'
|                                 ;   with `(make-add 2)'.
|           => (lambda (m) (+ n m))
|      (add2 4)                   ; Try to add 2 to 4.
|      error--> Symbol's value as variable is void: n
| 
|    Some Lisp dialects have "closures," objects that are like functions
| but record additional variable bindings.  Emacs Lisp does not have
| closures.
`----

Mais uma resposta da mailing list:

Emacs Lisp has dynamic scoping, not lexical scoping. If you want to emulate lexical scoping, (require 'cl-macs) and use lexical-let:

(defun foo (n)
  (lexical-let ((lexn n))
    (lambda (i)
      (incf lexn n))))

Etiquetas: Lisp, Emacs, Paul Graham, bug


Citações de "O homem sem qualidades" de R. Musil

2010/02/02-11:24:45

"E como a posse de qualidades pressupõe uma certa alegria pela sua realidade, é legitimo prever que alguém a quem falte o sentido de realidade até em relação a si próprio possa um belo dia, sem saber como, encarar-se como um homem sem qualidades." R. Musil, HsQ, pg. 43

"... quando andava pelas ruas - muito mais excitante era ainda andar de eléctrico!- costumava contar, e isto já levava anos, os segmentos de recta nas grandes letras das tabuletas das lojas (o A, por exemplo, tinha três, o M quatro), dividindo o seu número pelo número de letras. Até agora, a média mantinha-se invarialvelmente nos dois e meio.É claro que este número não era definitivo, e podia mudar com cada nova rua; assim, cada divergência trazia grandes preocupações, e cada coincidência grandes alegrias, o que correspondia aos efeitos catárticos atribuídos à tragédia. Mas quando somos nós a contar as letras, constataremos... que a divisibilidade por três é um caso raro, pelo que a maior parte das tabuletas deixam em nós uma sensação de clara insatisfação, à excepção daquelas que apresentam várias letras de grande intensidade, por exemplo WEM, e que em qualquer circunstância nos deixam particularmente felizes. E que consequências é que isto tem?... Nada mais nada menos do que isto: o Ministério da Saúde Pública deveria editar uma portaria com a finalidade de bonificar, na escolhas dos nomes das firmas, sequências de letras com quatro segmentos de recta, reprimindo na medida do possível as que só têm uma linha, como o O, o I e o C, já que a sua pobreza de traços é causadora de grande tristeza!" R. Musil, HsQ, pg. 465

Implementei então esta última actividade, em Emacs Lisp, para a contagem do número médio de traços das letras em palavra ou frases.

Implementação em Emacs Lisp

Aqui ficam as funções em Lisp que calculam ao número médio de segmentos de uma frase/texto.

(setq list-n (list  '(" " . 0.0) '("A" . 3.0)  '("B" . 3.0) '("C" . 1.0) 
'("D" . 2.0) '("E" . 4.0) '("F" . 3.0) '("G" . 2.0) '("H" . 3.0) '("I" . 1.0) 
'("J" . 1.0) '("K" . 3.0) '("L" . 2.0) '("M" . 4.0) '("N" . 3.0) '("O" . 1.0) 
'("P" . 2.0) '("Q" . 2.0) '("R" . 3.0) '("S" . 1.0) '("T" . 2.0) '("U" . 1.0) 
'("V" . 2.0) '("W" . 4.0) '("X" . 4.0) '("Y" . 3.0) '("Z" . 3.0) '("a" . 3.0)  
'("b" . 3.0) '("c" . 1.0) '("d" . 2.0) '("e" . 4.0) '("f" . 3.0) '("g" . 2.0) 
'("h" . 3.0) '("i" . 1.0) '("j" . 1.0) '("k" . 3.0) '("l" . 2.0) '("m" . 4.0) 
'("n" . 3.0) '("o" . 1.0) '("p" . 2.0) '("q" . 2.0) '("r" . 3.0) '("s" . 1.0) 
'("t" . 2.0) '("u" . 1.0) '("v" . 2.0) '("w" . 4.0) '("x" . 4.0) '("y" . 3.0) 
'("z" . 3.0) '("á" . 4.0) '("á" . 4.0) '("à" . 4.0) '("é" . 5.0) '("í" . 2.0) 
'("ó" . 2.0) '("ú" . 2.0) '("â" . 5.0) '("ã" . 5.0) '("ê" . 6.0) '("ô" . 3.0) 
'("Á" . 4.0) '("Â" . 4.0) '("À" . 4.0) '("É" . 5.0) '("Í" . 2.0) '("Ó" . 2.0) 
'("Ú" . 2.0) '("Â" . 5.0) '("Ã" . 5.0) '("Ê" . 6.0) '("Ô" . 3.0) '("." . 0.0) 
'("," . 0.0) '(":" . 0.0) '(";" . 0.0) '("-" . 1.0) '("ç" . 2.0)))

(defun string-to-strings (s)
    "Convert a string into a list of strings."
    (let ((i (- (length s) 1)) (l '()))
      (while (<= 0 i)
        (setq l (cons (aref s i) l)
              i (- i 1)))
      (mapcar (lambda (x) (char-to-string x)) l)))

(defun get-number-straight-lines-letter (s)
  (cdr (assoc (car s) list-n)))

(defun get-number-straight-lines-list-of-letters (s)
  (if (not s)
      0
    (if (stringp (car s))
        (+ (get-number-straight-lines-letter s) 
           (get-number-straight-lines-list-of-letters (cdr s)))
      (get-number-straight-lines-list-of-letters (cdr s)))))

(defun number-straight-lines-sentence (s)
  (/ (get-number-straight-lines-list-of-letters  
      (string-to-strings s)) (length s)))

Alguns exemplos

A expressão "Esta última sugestão" tem 2.05 segmentos, enquanto o meu nome "Tiago" tem 1.8. Segue uma pequena tabela (sugestões para mais palavras são bem vindas):

Palavra
Musil 1.8
Bach 2.5
diale 2.4
qualidades 2.1
Sócrates 2.125

Etiquetas: Musil, homem sem qualidades, citações


Quadricas

2010/02/02-11:24:45

Parabolóide hiperbolico.
Parabolóide hiperbolico.

Etiquetas: matemática, quadricas


QR code

2010/02/02-11:24:45

Isto é o QR code

para o diale.org

Etiquetas: QR, code, diale.org


Preferências

2010/02/02-11:24:45

A construção de poemas aleatórios tem, ao contrário da prosa, uma boa aceitação. Uma das razões está relacionada com o facto de os algoritmos que os geram produzirem textos com uma fraca conectividade semântica. Como é atribuída ao poeta a autorização de quebrar algumas regras somos naturalmente levados a interpretar o texto como se as regras quebradas fossem poesia e não a outra coisa que são. Aceitamos melhor a metáfora como alternativa ao sem-sentido. Ainda bem.

P. S.

Acreditem ou não, isto foi escrito ao som do Concerto Suite para guitarra eléctrica e orquestra em Mi menor op. 1 de Yngwie Malmsteen. Lembra qualquer coisa de JSBach, mas ainda não descobri o quê!?

Etiquetas: poemas aleatórios, Lisp, Bach, Malmsteen


Mais alguns exemplos de poemas concretos

2010/02/02-11:24:45

Indefinido de Liberto Cruz

latex2png equation

Despossuindo de Liberto Cruz

latex2png equation

Pouca-terra

latex2png equation

Etiquetas: Poesia concreta, Liberto Cruz


Palavras chave: página pessoal, blog, vida-exacta

Bookmark and Share

 

1999-2010 (c) Tiago Charters de Azevedo

São permitidas cópias textuais parciais/integrais em qualquer meio com/sem alterações desde que se mantenha este aviso.