segunda-feira, 17 de outubro de 2011

Racket

Racket Outro dia procurando por um bom interpretador/compilador para R⁶RS, encontrei algo muito mais interessante…

Encontrei o RAD-IDE Racket, antigo DrScheme.

O interessante do Racket é que, além de ser um interpretador e compilador de R⁵RS e R⁶RS, também suporta – aliás, por padrão – uma linguagem de programação baseada em Scheme, também chamada Racket – antiga PLT Scheme –, muito poderosa; também traz um ambiente de desenvolvimento chamado DrRacket.

Quando você escreve um script em Scheme, a primeira linha indica a versão que você pretende usar:
#!r4rs

Ou:
#!r5rs

Ou:
#!r6rs


Se o interpretador suportar a versão, ela será usada. Já no caso do Racket, outras opções são suportadas, como o padrão:
#lang racket

Para a linguagem padrão.

[update 2011-10-18]
Um script R⁶RS começa sempre com um import, por exemplo:
#!r6rs
(import (rnrs))


Você pode ter as funções de R⁶RS em um código Racket (PLT), basta usar:
#lang racket
(require rnrs)


O módulo rnrs traz toda a funcionalidade de R⁶RS.

Outra coisa legal da linguagem Racket é que, em vez de lambda, você pode usar λ (⌘\ / C-\).
[/update]


E até mesmo:
#lang planet jaymccarthy/c

Para linguagem de programação C – uma opção de C interpretado!

Para tanto você precisa ter em seu ~/.racketrc o seguinte conteúdo:
#lang racket
(require (planet jaymccarthy/c:1:2))


Para instalar o módulo C, você pode executar no widget de definições (⌘D no Mac OS X, C-d no Windows e no GNU/Linux):
> (require (planet "main.rkt" ("jaymccarthy" "c.plt" 1 2)))


[update 2011-10-18]
Eu acho que você não precise instalar o módulo, basta colocar sua chamada em ~/.racketrc e, na primeira execução, o módulo será automaticamente baixado e instalado.

Só não posso afirmar com certeza porque eu já havia instalado ele antes.

No Windows, o arquivo é racketrc.rktl e deve ficar no diretório de perfil do usuário.
[/update]


Programação visual


Para facilitar a vida de quem precisa desenvolver aplicações gráficas, você pode usar o MrEd Designer.

Para instalá-lo, execute no widget de definições do DrRacket:
> (require (planet orseau/mred-designer:3:7))


Para iniciar o processo, use (recomendo criar um alias):
bash$ gracket -e '(require (planet orseau/mred-designer:3:7))'


Olá Mundo!


Vamos criar um programa simples. Primeiro abra o MrEd Designer.

[update 2011-10-19]
Troquei os nomes dos widgets pelos nomes usados no código Racket.
[/update]


Na janela Hierarchy selecione project-XXX.

Na janela MrEd Designer, na seção Containers, clique no primeiro botão, frame%.

Vai surgir uma janela pequena e, na hierarquia do projeto, um frame% (frame-XXXX) sob o projeto.

Na janela Hierarchy selecione o frame% que apareceu e repare que a janela Properties mudou.

Em Properties, mude o valor de label (que está Frame) para Olá Mundo! e clique em Save & Update Preview.

Veja que o título da janela mudou.

Agora, ainda com o frame% selecionado, na janela MrEd Designer, na seção Controls, clique no primeiro botão, message%. Repare que surgiu um elemento message% (message-XXXX) na hieraquia, sob o frame%.

Selecione o novo elemento e mude o label (em Properties) para Olá Mundo!.

Clique em Choose Font… e escolha uma fonte maior, sugiro Arial Bold 20, e clique em Ok.

Clique novamente em Save & Update Preview.

Selecione de novo o frame% em Hierarchy e, em MrEd DesignerControls, clique no segundo botão, button%.

Surgirá um elemento button% (button-XXXX) sob o frame%. Selecione-o.

Mude o label para Ok e a fonte para Arial 14. Clique em Save & Update Preview.

Agora, na janela MrEd Designer, no menu File clique em Save Project – ou pressione ⌘S / C-s. Escolha o diretório e salve como ola.

Depois clique em FileGenerate Scheme File… – ⌘F5 no Mac. Salve como ola.ss no mesmo diretório onde você salvou o projeto.

Repare que você terá dois arquivos: ola.*.med (o projeto) e ola.ss (o código).

Abra agora o arquivo ola.ss no DrRacket:
bash$ drracket ola.ss


Procure a seguinte linha:
(button-XXXX-callback (lambda (button control-event) (void))))


Onde XXXX é uma sequência de dígitos decimais.

Mude para:
(button-XXXX-callback (lambda (button control-event) (displayln "Olá Mundo!"))))


Veja a linha 8 do script:
;;; Call (project-XXX-init) with optional arguments to this module


Acrescente a linha sugerida ao final do arquivo:
(project-XXX-init)


Salve o arquivo – ⌘S / C-s – depois rode/corra o programa – ⌘T / C-t – e veja a mágica.

Para executar o script sem precisar levantar o DrRacket, use o comando:
bash$ gracket ola.ss


Se preferir tornar o script executável, acrescente a primeira linha:
#!/usr/bin/env gracket


Outros recursos


Você pode encontrar uma série de módulos interessantes no PLaneT, como facilidades web, conexão a banco de dados, bzlib, Plan9, JSON, etc.

Sobre construção de aplicações web, leia Continue: Web Applications in Racket.

[]’s
Cacilhας, La Batalema

sábado, 15 de outubro de 2011

R.I.P. Dennis Ritchie

Artigo original nas Reflexões de Monte Gasppa e Giulia C..

Dennis Ritchie No mesmo mês em que morreu o mago da distorção da realidade, também nos deixa Dennis Ritchie, criador das linguagens de programação B (baseada em APL) e C e cocriador do sistema operacional UNIX.

Se Steve Jobs esteve envolvido direta ou indiretamente com cada avanço tecnológico que não fosse voltado para resolver problemas da própria máquina, salvo raríssimas exceções, Dennis Ritchie foi o criador da linguagem de programação – e dos conceitos envolvidos – usada como base para quase todas as linguagens modernas, além de ter participado ativa e diretamente da criação do sistema operacional que serve de base para todos os sistemas atuais que funcionam.

A parte mais triste é ver todo o bafafá em cima do falecimento de Jobs, mas nada se fala de Ritchie, tão importante quanto. Ou pior… vi programadores que não sabem quem foi Dennis Ritchie!

Como eu disse, um programador que não conheça Dennis Ritchie, Dijkstra e Knuth precisa mudar de profissão ou tomar muita porrada.


[]’s
Cacilhας, La Batalema

quarta-feira, 14 de setembro de 2011

Falsa indução ou a falácia da metodologia infalível

Glider Reza a lenda que um código bem testado é um código sem bugs.

Além de não acreditar em código sem bugs, ainda há um problema com a definição de «bem testado».

Hoje em dia os evangelistas das novas velhas metodologias de programação defendem que a experiência profissional seja secundária – quiçá irrelevante – caso as metodologias agile sejam corretamente aplicadas, e uma das regras de outro é entupir o código de testes.

Porém quantidade não é qualidade. Não adianta encher o código de testes se você não tem feeling sobre o que testar – e feeling só se adquire com experiência profissional.

Há uma série de armadilhas prontas para pegar os incautos que se creem blindados pelas metodologias.

Uma armadilha comum é a falsa indução.

Por exemplo, tenho um código que calcula a raiz quadrada e trinta testes para ele, todos passando:
bash$ nosetests
..............................
----------------------------------------------------------------------
Ran 30 tests in 0.013s

OK


No entanto, quando eu tento alguns valores:
bash$ python
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from sqr import sqr
>>> sqr(16) # 4
7
>>> sqr(25) # 5
7
>>> sqr(144) # 12
45
>>> sqr(225) # 15
27
>>> sqr(256) # 16
58


Valores completamente loucos! Isso porque o código caiu em uma falsa indução:
# coding: UTF-8

from math import ceil

__all__ = ['sqr']

def sqr(num):
d = 10 ** int(ceil(len(str(num)) / 2.))
return (num % d) + (num // d)


É claro que uma boa metodologia, como TDD, é um ferramenta poderosíssima nas mãos de um programador experiente, mas pode se tornar uma arma de autodestruição nas mãos de um novato com excesso de confiança.

Então repito o conselho de um autor que escreveu, mais ou menos isto: não aprenda a programar em dez horas ou em dez dias; aprenda a programar em dez anos.

[]’jn
Cacilhας, La Batalema


PS: Você pode baixar os testes de http://cacilhas.info/falsa-inducao/tests.py. Repare que se substituir:
from sqr import sqr

por:
from math import sqrt as sqr

os testes continuam passando.

terça-feira, 12 de julho de 2011

Prolog

Certamente Prolog não é meu forte… nunca fiz nada útil em Prolog e não conheço a linguagem tanto quanto gostaria, mas já tive meu samadhi.

Prolog é uma linguagem de programação declarativa de propósito geral, voltada para inteligência artificial e linguística computacional.

Seu nome significa programmation en logique e foi criada no começo da década de 1970 por um grupo liderado por Alain Colmerauer em Marseille, França.

Predicados e domínio


A programação Prolog consiste em definir um conjunto de verdades chamadas fatos e relações entre os fatos, chamadas regras.

De um modo geral, fatos e regras são chamados predicados e o conjunto de predicados do programa é chamado domínio do problema.

Um fato define uma afirmação, uma verdade:
flor(cravo).


Esta linha de código está dizendo «cravo é uma flor», e é um predicado do domínio.

Regra é um predicado condicional:
gosta(ana, X) :- flor(X).


Ana gosta de X se X for uma flor, ou de forma mais precisa: se Ana gosta de X implica que X é um flor, ou seja, leia :- como implica em.

Lembre-se que implicância é uma operação não recíproca.

Consultas


O uso de Prolog se dá através de consultas (queries). Por exemplo, salve as duas linhas acima no arquivo ana.pro, execute o interpretador e digite:
| ?- [ana].
compiling ~/ana.pro for byte code...
~/ana.pro compiled, 2 lines read - 419 bytes written, 14 ms

(1 ms) yes
| ?- gosta(ana, cravo).

yes
| ?- gosta(ana, gato).

no


Tipos


Prolog possui quatro tipos: átomo, termo composto, número e lista. Um fato precisa ser um átomo ou um termo composto.
  • Átomo: é uma constante. Representado por uma sequência de letras, números e underscore iniciada por uma letra minúscula ou uma sequência entre plicas. Ex.: cravo, 'ana.pro', 'Cacilhας, La Batalema'.

  • Termo composto: é uma estrutura complexa. Consiste em um funtor seguido por um ou mais parâmetros entre parêntesis. O funtor deve ser um átomo, os parâmetros podem ser de quaisquer tipos. Ex.: gosta(ana, gato).

  • Número: exatamente o que diz. É representado por dígitos numéricos e ponto (para ponto flutuante.) Ex.: 123, 3.1415.

  • Lista: é uma sequência de elementos de outros tipos. Os delimitadores de início e fim são [] e os elementos são separados por vírgulas. O símbolo pipe (|) por ser usado para representar resto da lista. Ex.: [a, b, c], [abc | SX] (SX é uma lista).

  • String: é um tipo especial de lista que contém apenas números inteiros entre 0 e 255. Ex.: "ABC"[65, 66, 67].


Incógnita


O equivalente a variável em Prolog é a incógnita, que consiste em um valor desconhecido, porém constante, representado por uma sequência similar ao átomo, mas iniciada por uma letra maiúscula.

Por exemplo, em:
gosta(ana, X) :- flor(X).


X é uma incógnita. A solução das consultas feitas acima é obtida encontrando o valor de X, o que é responsabilidade do programa.

Exemplo


Um exemplo clássico de Prolog é a implementação de fatorial:
factorial(0, 1).

factorial(N, F) :-
N > 0,
N1 is N - 1,
factorial(N1, F1),
F is N * F1.


O que o código diz é que o fatorial de 0 é 1 e se o fatorial de N é F implica que:
  • N é maior que 0 (já está coberto pelo predicado anterior);
  • N1 é igual a N menos 1;
  • O fatorial de N1 é F1;
  • E F é igual a N vezes F1.


Uso:
| ?- [factorial].
compiling ~/factorial.pro for byte code...
~/factorial.pro compiled, 7 lines read - 941 bytes written, 14 ms

(1 ms) yes
| ?- factorial(5, X).

X = 120 ?

yes


Um bom exemplo também é a implementação da solução da torre de Hanói, mas vai fritar seu cérebro:
hanoi(N) :- move(N, esquerda, direita, central).

move(1, X, Y, _) :-
write('mova o disco da torre '),
write(X),
write(' para a torre '),
write(Y),
nl.

move(N, X, Y, Z) :-
N > 1,
M is N - 1,
move(M, X, Z, Y),
move(1, X, Y, _),
move(M, Z, Y, X).


É claro que isso não é nem o começo. O objetivo é apenas causar água na boca.

[]’s
Cacilhας, La Batalema

domingo, 13 de março de 2011

Decoradores em Lua

@



Um recurso extremamente útil em Python é o uso de decoradores.

Por exemplo, um decorador que memoíze o resultado de uma função:

def memo(func, buffer={}):
def wrapper(*args):
if args in buffer:
response = buffer[args]
else:
response = buffer[args] = func(*args)
return response

return wrapper


Assim funções como o cálculo recursivo da sequência de Fibonacci se tornam menos custosas:
@memo
def fibonacci(n):
if n < 2:
return 1
else:
return fibonacci(n - 2) + fibonacci(n - 1)


Observação: memoização consome muita memória!

É possível ver que, em Python, decoradores são extremamente fáceis de se implementar e usar, o que permite usos bastantes complexos, como a orientação a aspecto.

Lua também suporta decoradores, mas de uma forma um pouco menos intuitiva, mais complexa e totalmente macetada.

Para a criação de decoradores em Lua, é usada a sobrecarga do operador de concatenação, como sugerido na literatura de referência.

Para criarmos então o decorador de memoização, precisamos de uma metatabela que sobrecarregue o operador:
local mt = {
__concat = function(self, func)
return function(...)
local response
local args = serialize(...)
if self[args] then
response = self[args]
else
response = func(...)
self[args] = response
end
return response
end
end,
}


A função serialize() não existe, então temos de criá-la:
local function serialize(...)
local response = ""
local i, v
for i, v in ipairs {...} do
response =
response .. "[" .. ("%g"):format(i) .. "] = " ..
("%g"):format(v) .. ", "
end
return response
end


Agora criamos o decorador:
function memo()
return setmetatable({}, mt)
end


Isso tudo pode ser colocado em módulo, chamado memo.lua por exemplo. Na última linha do módulo coloque:
return memo


Agora, para usar o decorador:
require "memo"

fibonacci =
memo() ..
function(n)
if n < 2 then
return 1
else
return fibonacci(n - 2) + fibonacci(n - 1)
end
end


O uso do decorador está na linha: memo() .. – a sintaxe não é tão elegante quanto a de Python – @memo –, mas funciona da mesma forma, inclusive a criação de cadeias de decoradores.

A criação de decoradores em Lua também não é tão intuitiva e simples quanto em Python, em função da diferença de filosofias entre as duas linguagens, mas com o hábito se torna um recurso poderoso.

[]’s
Cacilhας, La Batalema

sábado, 5 de fevereiro de 2011

Álgebra Booleana e falácias

Glider Outro dia eu estava conversando com um amigo meu sobre um problema que nos incomoda bastante, que é o fato das pessoas não conhecerem nem o mínimo de lógica aplicada. Nem mesmo as operações básicas.

Em função disso as pessoas são enganadas pelas mais triviais das falácias, como acidente, afirmação do consequente, negação do antecedente, Red Herring e pressuposição aplicada a conjuntos de axiomas.

Vejo tais falácias chulas nos mais diversos textos, geralmente usados para defender ideias da moda. Pensando nisso, eu e meu amigo decidimos que eu deveria escrever este artigo explicando o básico da Álgebra Booleana, que também é totalmente relevante para programadores.

Pensamento binário


A Álgebra Booleana é baseada no concento de verdades: cada proposição é uma afirmação que pode ser verdadeira ou falsa e é representada em sua forma mais simples por uma letra maiúscula.

Quando uma proposição aparece sozinha, assume-se que ela é verdadeira.

Por exemplo:
    A


Indica que a proposição A é verdadeira.

O operador ¬ indica negação, então:
    ¬A


Indica que a negação da proposição A é verdadeira, ou seja, que a proposição A é falsa.

Operações booleanas


Assim como na Álgebra Elementar, a Álgebra Booleana possui operações, chamadas operações lógicas.

As operações mais conhecidas são: E lógico (∧), OU lógico (∨), OU exclusivo (⊕), implicação (→) e equivalência (↔), além da negação (¬), que já vimos.

E lógico


A operação E lógico relaciona duas proposições e a expressão formada é verdadeira se as duas proposições forem verdadeira, caso contrário é falsa.

A tabela é:
+---+---+-----+
| A | B | A∧B |
+---+---+-----+
| V | V | V |
| V | F | F |
| F | V | F |
| F | F | F |
+---+---+-----+


Ou seja, a seguinte afirmação:
    A∧¬B


Indica que tanto A quanto ¬B são verdadeiros, ou, de modo mais simples, que A é verdadeiro e B é falso.

OU lógico


A operação OU lógico relaciona duas proposições e a expressão resultante é verdadeira se qualquer uma das duas proposições for verdadeira, caso contrário é falsa.
+---+---+-----+
| A | B | A∨B |
+---+---+-----+
| V | V | V |
| V | F | V |
| F | V | V |
| F | F | F |
+---+---+-----+


Por exemplo:
    A∨B


Indica que A é verdadeiro, B é verdadeiro ou ambos são, não permitindo que saibamos qual dos casos, nos obrigando a apelar a outra expressão para descobrir.

Então:
    A∨B
¬A


Sabemos então que A não é verdadeiro, restando apenas uma opção para validar a expressão, que é quando B é verdadeiro. Podemos escrever isso da seguinte forma:
    A∨B
¬A
├ B


O sinal ├ significa «cocluímos que…». Então, se A ou B é verdadeiro e A é falso, concluímos que B é verdadeiro.

Falácia do OU lógico


Repare na tabela que dizer que um dos elementos é verdadeiro não garante que o outro seja verdadeiro ou falso, ou seja, tanto V∨F quanto V∨V são verdadeiros. Daí concluir:
    A∨B
A
├ ¬B


É um erro!

Por exemplo, digamos que sabemos que alguém nadou na piscina, pois as bordas estavam molhadas. As suspeitas são Pedro e João. Sabemos que Pedro nadou na piscina, logo deduzimos que João não nadou.

Ora! O fato de Pedro ter nadado na piscina não significa que João não tenha nadado também.

OU exclusivo


Esta operação é o OU a que estamos mais habituados na linguagem comum. Ou uma proposição é verdadeira, ou outra, mas não as duas:
+---+---+-----+
| A | B | A⊕B |
+---+---+-----+
| V | V | F |
| V | F | V |
| F | V | V |
| F | F | F |
+---+---+-----+


Geralmente não tem consequências maiores, a menos quando o OU lógico é confundido com o OU exclusivo, como na falácia anterior.

Implicação


A implicação é a operação lógica mais explorada pelos maliciosos que pretendem enganar os desavisados.

Funciona da seguinte forma: se a primeira proposição for verdadeira, a segunda também será, caso contrário nada se sabe da segunda proposição.

A tabela diz o seguinte:
+---+---+-----+
| A | B | A→B |
+---+---+-----+
| V | V | V |
| V | F | F |
| F | V | V |
| F | F | V |
+---+---+-----+


Então a conclusões que podemos tirar são:
    A→B
A
├ B

A→B
¬B
├ ¬A


Afirmação do consequente


É quando se usa a consequência para afirmar o antecedente:
    A→B
B
├ A


Veja na tabela que tanto V→V quanto F→V são verdadeiros, assim afirmando o consequente não é possível dizer nada do antecedente. É uma falácia!

Por exemplo (da Wikipédia): onde há carros, há poluição. Portanto, se há poluição, deve haver carros.

Negação do antecedente


É quando se usa a negação do antecedente para negar a consequência:
    A→B
¬A
├ ¬B


Veja na tabela que tanto F→V quanto F→F são verdadeiros, então se o antecedente for falso, nada se sabe da consequência.

Por exemplo: se o rio for fundo, é possível que haja crocodilos. Como o rio não é fundo, não deve haver crocodilos.

Equivalência


A equivalência diz que as duas proposições são falsas ou que as duas são verdadeiras:
+---+---+-----+
| A | B | A↔B |
+---+---+-----+
| V | V | V |
| V | F | F |
| F | V | F |
| F | F | V |
+---+---+-----+


Seu perigo é quando a operação de implicação é confundida com ela.

Acidente


Acidente consiste em tomar o todo pela parte. Se há religiosos fanáticos, então todo religioso é fanático; ou: se há ateus não fanáticos, então nenhum ateu é fanático. Conclusões erradas.

As operações envolvidas são um pouco mais complexas, ∃ (existe) e ∀ (para todo). Não vou entrar nesse mérito, já que foge ao escopo do artigo.

Red Herring


Consiste em distrair o interlocutor com afirmações (geralmente verdadeiras) que não têm relação de consequência com a conclusão.
    A
B
C
D
├ E


Por exemplo: este prédio sofre muita infiltração devido à grande quantidade de pinturas de paisagem oceânica pelas paredes.

Costuma ser muito usada em combinação com as falácias de afirmação do consequente e de negação do antecedente, para que o interlocutor se distraia e não as perceba.

Pressuposição de axiomas


A pressuposição é a falácia onde uma verdade não comprovada é pressuposta para validar uma consequência:
    A→B
├ B


Mas geralmente é óbvia demais, então é usada com conjuntos de axiomas.

Axiomas são afirmações que se intervalidam, garantindo que ou todas são corretas, ou todas são falsas:
    A→B
B→C
C→D
D→A
├ A


É interessante lembrar que, ao contrário do que os defensores ferrenhos da onisciência da Ciência Humana dizem, o conhecimento científico oficial é baseado mais em conjuntos de axiomas – e até alguns postulados – do que em observação e prática.

--


Fica então a dica: não se deixe enganar por falácias!

Você pode encontrar mais sobre falácias na Wikipédia.

E a Álgebra Booleana é amplamente utilizada na programação.

[]’s
Cacilhας, La Batalema