Mostrando postagens com marcador Programação. Mostrar todas as postagens
Mostrando postagens com marcador Programação. Mostrar todas as postagens

2013-10-14

Tipagem de dados em programação

Heim? Eu já havia determinado que assuntos de programação seriam publicados no Kodumaro, deixando este blog pro meu blá-blá-blá habitual.

No entanto surgiu um assunto sobre programação que é, ao mesmo tempo, reclamação minha.

Sei que programadores de linguagens de tipagem fraca e dinâmica e programadores de linguagens de tipagem forte e estática têm dificuldade em diferenciar tipagem fraca de dinâmica e tipagem forte de estática, porém isso está chegando a um extremo de eu ler essa confusão em livros didáticos!

Chega dessa confusão, vou tentar explicar um pouco.

Resistência a coerção

Toda linguagem de programação possui tipos de dados e coerção ou conversão entre tipos. Quanto mais variados e bem definidos os tipos da linguagem, mais difícil é a coerção entre eles e diz-se que a linguagem é mais forte. Muitas linguagens de tipagem forte chegam a requerer um coerção explícita, chamada typecasting.

Linguagens com poucos tipos ou cuja diferença entre os tipos seja fraca, são chamadas de tipagem fraca.

Por exemplo, duas linguagens de tipagem fraca são Javascript e Lua:
value = 12
value = value + "2"

A sentença acima é válida tanto em Javascript quanto em Lua e, nas duas, o valor final da variável value é 14.

Isso acontece porque, como o primeiro parâmetro da soma era um número inteiro, o segundo parâmetro (a string "2") foi implicitamente convertida para seu equivalente numérico.

Esse tipo de mágica pode gerar problemas desagradáveis e erros difíceis de serem depurados, mas é uma abordagem válida se o programador decidir conviver com isso.

Já linguagens de tipagem forte, como Python e Java, geram exceções caso você tente usar um objeto como se fosse de um tipo diferente dele:
>>> value = 12
>>> value = value + "2"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Como você pode ver, Python reclama imediatamente do tipo. É preciso executar uma coerção explícita.

Quem determina o tipo?

Outra questão é, havendo tipos definidos, quem determina o tipo.

Se o tipo de um dado é determinado por seu container, a variável que o referencia, a tipagem é dita estática. Por exemplo, Java e C são linguagens de tipagem estática.

Já quando o próprio dado já possui seu tipo auto-contido, independente de quem o referencie, a tipagem é chamada dinâmica. Python e Erlang possuem tipagem dinâmica.

Agora, repare uma coisa: uma linguagem ser forte ou fraca não tem nada a ver com ela ser estática ou dinâmica. Vimos diversos exemplos:
  • Lua e Javascript possuem tipagem fraca e dinâmica.
  • Python e Erlang possuem tipagem forte e dinâmica.
  • Java possui tipagem forte e estática.
  • C possui tipagem fraca e estática.
Sim! A tipagem de C é fraca e estática, ao contrário do que muita gente pensa. A coerção entre tipos de C é muito simples, basta você usar ponteiros de tipos diferentes para referenciar o mesmo valor – mesmo que o resultado não seja o esperado por quem programa em outras linguagens de tipagem fraca:
char var_1[] = "A";
unsigned char *var_2;
var_2 = var_1;

O valor de *var_1 será a string "A", enquanto o valor de *var_2 (ponteiro que aponta para o mesmo dado na memória) será 65. O tipo é atribuído pelo ponteiro/variável.

Portanto, ao contrário do que muita gente prega, uma linguagem pode ter tipagem estática e fraca sim.
[update 2013-10-16]
O valor de *var_2 ou var_2[0] será 65, mas o valor de var_2[1] será 0.

Isso ocorre porque em C strings são listas de caracteres terminadas com nulo (\000).
[/update]

Creio que isso possa ter esclarecido algumas coisas que as pessoas repetem por aí à moda Goebbels.

[]’s
Cacilhας, La Batalema

2013-08-09

O programador positivo

Kenpachi Artigo muito bom tirado do blog Randall Degges – Random Thoughts of a Happy Programmer:

Is it just me, or is the technical community developing a more and more negative outlook in recent years? I hate to complain, but it seems like every week the development community is up in arms about some huge outrage, whether it be regarding code of conduct policies, sexism, startup criticism, craftsmanship, or any other topic.

If you’re a programmer and stay up-to-date with community happenings via Hacker News, you’ll almost certainly notice a trend: there are lots of popular articles focusing on the negatives (mean rants, public shaming, outrage about various issues, etc.). And if you happen to participate in article discussion, you’ll get an even greater taste of the negative attitudes becoming more and more pervasive in the community: articles flooded with a mix of slanderous (and more frequently, downright mean) comments that really bring everyone down =/

Personally, I like to focus on the positive. ^^

The Problem with Negativity

My problem with negativity comes primarily from personal experience. I wasn’t always as happy as I am now, and I certainly didn’t have a positive attitude most of my life.

Several years ago I had just left university (I dropped out after my second year of computer science), and decided to start working in the field. While I’ve always loved programming, throughout my university experience I was one of the most negative people I’ve known. I was extremely judgemental, short of temper, and generally quick to dismiss other people and their ideas.

When I left school and started working in the field I realized exactly how miserable I really was: instead of being able to enjoy every day, enjoy my relationships, and enjoy my work – I was instead overly focused on the negatives: how unfair things were, how I deserved more, how other people were causing problems for me, and how I was vastly superior to everyone else.

I distinctly remember coming home from work and sitting in the bathtub one day, thinking about myself, and where I wanted to be in five years. The first (and only) thing that immediately came to mind was that I wanted to be a better person: I wanted to be smarter, more successful, and happy.

It wasn’t until that moment I realized that I was truly unhappy with my current self, and really needed to make some serious personal changes if I could ever enjoy my life. Being discontent with yourself is a horrible feeling. You feel angry, frustrated, and cheated. Am I doing something wrong? Why do I feel this way? Without realizing it, I had been turning my internal frustration and anger outwards, with horrible consequences.

It was at that moment I decided to actually focus on real personal development. Instead of allowing myself to play the victim and slowly let my frustration and anger eat away at me, I decided to take my future into my own hands and make whatever changes necessary to make myself a better person.

The Positive Programmer

In the beginning I had a really difficult time training myself to let go of my bad habits and negativity. Your personal outlook and mental response to every day situations is something that comes naturally. It takes a lot of energy, education, and practice to let go of bad behaviors and teach yourself new (healthier) behaviors.

After doing some basic Google research: How can I be happy?, How can I become a better person?, etc. – I realized that I needed to start out by re-educating myself. It’s very difficult to find answers to questions you don’t yet know.

The first thing I did was randomly pick a few highly reviewed personal development books on Amazon and read them. Instantly, I began to realize that improving yourself as a person is all about being positive.

Instead of focusing on the negative in life, focus on the positives. One of the most important truths I’ve learned came from my study of minimalism.

What is happiness really? Happiness is being content with yourself and your surroundings. What’s the best way to be content with yourself and your surroundings? To accept reality as it is.

All feelings of frustration, anger, and negativity are generated internally. If you’re driving down the freeway and another driver cuts you off, forcing you to slam on your brakes to avoid a collision – most people would get angry at the other driver. It’s a natural reaction, after all. The person ahead of you did something they shouldn’t do, which caused you an inconvenience. In your mind, they’ve done something that doesn’t align well with your version of reality, so your brain makes you feel angry and frustrated.

The simplest way to avoid getting angry and frustrated (not only with yourself, but with others as well) is to practice compassion. Instead of viewing the world through your own point of view, play the role of a calm observer. Accept the behavior of others as it is, and don’t allow yourself to project your desired behavior onto others. Instead of allowing yourself to get angry over situations you can’t control, learn to calmly accept them and carry on.

The ability to rationally analyze situations and make mindful decisions will not only help you maintain a positive outlook on life, but will help you feel happier, and allow you to focus on more important topics on a day to day basis.

Instead of wasting energy getting upset and angry with others, you can instead focus on doing the things that are important to you:
  • Enjoying your relationships.
  • Fully enjoying your work.
  • Taking control of your life and growing as a person.
Since I decided to invest time in making myself a better person, I’ve completely changed my day-to-day attitude, behavior, and outlook. Instead of feeling unhappy and discontent with myself, I’ve been able to build a great life that allows me to really enjoy each day.

Some Closing Thoughts

Living with a negative attitude is a horrible burden, something I wouldn’t wish on anyone. It really pains me to see so many of my peers stuck in a continuous cycle of negative thinking. Focusing on the negatives is the simplest way to:
  • Make yourself unhappy.
  • Sacrifice your personal development and growth.
  • Miss out on great opportunities and obvious ways to become a better person.
  • Alienate yourself from other great people doing great things.
My advice to you if you’re stuck in a rut like I was: make a commitment to yourself to focus on personal development – it’s never too late to get started.

Is it easy to recondition yourself? No way. It will be a slow process: nothing will happen overnight.

Take small steps. Here are some great ways to get started:
  • Pick up a good personal development book. Some good starting topics to research are minimialism, mindfulness meditation, happiness, procrastination, and talent. If those don’t sound immediately appealing, try reading a biography on someone you greatly respect.
  • Be mindful of your thoughts throughout the day. The next time you find yourself thinking What the hell is that person doing? take a second to think about why you feel that way. Are you angry? Are you overreacting? Don’t be angry with yourself, just acknowledge your thoughts and make a mental note of why you felt that way.
  • Remove negativity from your immediate surroundings. Easy ways to get started are to unfollow people on twitter who continuously tweet negative things, stop reading news, and don’t participate in negative conversations with friends and family.
  • Keep your goal in mind at all times. Throughout the day you should tell yourself (especially when you’re feeling negative) that your goal is to become a better person, and the only way to do that is to consciously work at it! If you need motivation, don’t feel bad about getting help: watching motivational videos, listening to your favorite songs, etc.
Reconditioning yourself to be a more positive person is no easy task, but I can tell you from experience that it’s worth every bit of effort you put into it. Changing your behavior is possible with enough focus, motivation, and rational thinking.

If you’re stuck in a rut and want someone to chat with, feel free to shoot me an email, I’d love to help!

Published: Tue 26 March 2013

2011-04-22

Perfil bash no OS X

GNU Um amigo meu sugeriu que eu escrevesse um artigo sobre como organizo meu perfil bash no Mac OS X. Eis aqui!

No OS X, assim como em qualquer sistema Unix-like, o bash lê o perfil basicamente de dois arquivos: /etc/profile e ~/.bash_profile (em muitos sistemas o /etc/profile carrega todos os scripts executáveis em /etc/profile.d/).

Só que deixar todas as configurações em um único arquivo pode torná-lo confuso. Para resolver esse problema, fiz o seguinte: criei um diretório ~/bin/profile e coloquei um código no ~/.bash_profile que carrega todos os scripts executáveis desse diretório.

O trecho de código é o seguinte:

for script in $HOME/bin/profile/*.sh
do
if [[ -x "$script" ]]
then
. "$script"
fi
done


Exemplo


Como exemplo, um de meus arquivos é o que ajusta as cores do terminal.

No OS X, o LSCOLORS é uma string de onze pares de caracteres. O primeiro carácter do par é a cor de frente (foreground) e o segundo a cor de fundo (background).

Os onze pares são em ordem:
  1. cores para diretório
  2. cores para ligação simbólica (symlink)
  3. cores para soquete
  4. cores para pipe
  5. cores para arquivo executável
  6. cores para arquivo especial de bloco
  7. cores para arquivo especial de carácter
  8. cores para executável com o bit setuid ajustado
  9. cores para executável com o bit setgid ajustado
  10. diretório gravável por outros, com stick bit ajustado
  11. diretório gravável por outros, sem stick bit ajustado


Os caracteres usados para ajustas as cores de cada parte (frente e fundo) de cada par são:
  • x o valor pré-definido
  • a preto
  • b vermelho
  • c verde
  • d marrom
  • e azul
  • f magenta
  • g ciano
  • h cinza


As mesmas letras em maiúsculas significam negrito.

Por exemplo, meu LSCOLORS é assim:
LSCOLORS=ExGxFxFxCxegedabagacad


Traduzindo:
  • Diretório Ex: frente azul em negrito, fundo padrão
  • Ligação simbólica Gx: frente ciano em negrito, fundo padrão
  • Soquete Fx: frente magenta em negrito, fundo padrão
  • Pipe Fx: idem ao anterior
  • Executável Cx: frente verde em negrito, fundo padrão
  • Especial de bloco eg: frente azul, fundo ciano
  • Especial de carácter ed frente azul, fundo marrom
  • Executável com setuid ab: frente preta, fundo vermelho
  • Executável com setgid ag: frente preta, fundo ciano
  • Diretório gravável por outros com stick bit ac: frente preta, fundo verde
  • Diretório gravável por outros sem stick bit ad: frente preta, fundo marrom


Mas é preciso ajustar também a variável de ambiente CLICOLOR e exportar tudo.

No final fica assim:
#-----------#
# LS colors #
#-----------#

LSCOLORS=ExGxFxFxCxegedabagacad
CLICOLOR=1
export CLICOLOR LSCOLORS

alias l='ls -lh -G'


Fazendo funcionar


Para fazer funcionar, o arquivo precisa ser executável. Meu arquivo de cores chama ~/bin/profile/colors.sh, portanto:
bash$ chmod +x ~/bin/profile/colors.sh


Outro exemplo


Outro exemplo é o arquivo que torna o Vim o editor padrão:
#-----#
# Vim #
#-----#

if [[ -z "$DISPLAY" ]]
then
EDITOR='/Applications/MacVim.app/Contents/MacOS/Vim'
else
EDITOR='/Applications/MacVim.app/Contents/MacOS/Vim -g --nofork'
fi
export EDITOR


Veja que a graça da brincadeira é a modularização, que deixa configurações de coisas diferentes em arquivos diferentes e configurações da mesma coisa encapsuladas.

**
Fica então mais esta dica!

[]’s
Cacilhας, La Batalema

2011-02-06

Águas DO Imperador

Silent Hill Petrópolis/RJ é uma cidade provinciana, atrasada e burguesa, onde a aristocracia é sempre defendida. Famílias quatrocentonas e seus aliados podres de ricos controlam as empresas que monopolizam os serviços da cidade.

Um exemplo é o monopólio da Única Fácil, que controla a ponte rodoviária Petrópolis-Rio, a praticar os preços que bem entende.

E a prefeitura nada faz: apesar de ter-se elegido pelo PT, o prefeito é pau mandado aliado de Leandro Sampaio, que, quando geriu a prefeitura de Petrópolis pelo PSDB, sucateou o sistema de saúde, num óbvio esforço de favorecer as empresas de plano de saúde. Só não vê quem não quer.

Mas tudo o que eu disse foi apenas para dar contexto ao problema que temos com a empresa de águas e esgoto, Águas do Imperador.

Como o nome sugere, a empresa trata as águas não como um bem público a ser administrado, mas como propriedade do imperador. Assim a empresa cobra pelo consumo da água de poços e nascentes particulares como se fosse fornecida por ela; cobra pelo uso de tubulações de esgoto de mais de 80 anos, construídas pelos próprios moradores; cobra pelo tratamento do esgoto, que é jogado in natura nos rios; e ainda faz cagadas como esta:
Em frente ao Hospital Santa Teresa

Só quem faz merda precisa esconder o trabalho assim, bloqueando a visão de um cruzamento, o que expõe os moradores a potenciais acidentes de trânsito que poderiam facilmente ser evitados.

Porém toda minha reclamação aqui é em vão, já que o povo petropolitano, provinciano e a favor do Neoliberalismo, acha tudo isso muito natural e até desejável.

[]’s
Cacilhας, La Batalema

2010-08-10

Pomposo ultradireitista expõe preconceito regional

Baal Meu amigo Walter Cruz me recomendou a leitura de uma discussão no grupo Lisp-br chamada Pedido.

Nela um holandês chamado Joop Kiefte pede informações sobre moradia e emprego no Brasil:

Olá!

Eu sou da Holanda e chegarei logo no Brasil para morar aí. Quero perguntar se vocês sabem de casa não caro demais perto de Rio ou Salvador, e/ou de trabalho que posso fazer aí.

Obrigado pela sua atenção!

Joop


Um sionista ou nazista chamado Rafael Ibraim deu uma resposta preconceituosa e ultradireitista:
Como nos últimos anos o governo tem desviado o (nosso) dinheiro para a região norte/nordeste em grande quantidade, talvez seja mais fácil encontrar um emprego no norte… Não conheço os preços no Rio, mas sei que no norte as cidades *próximas* às capitais tem preços até bem
acessíveis…

Caso você nunca tenha visitado o Brasil, atenção: Os estados brasileiros que estão fora da região sul/sudeste costumam ter uma *péssima* infra-estrutura (estradas, sinalização, etc.) mesmo em locais turísticos. Recomendo pesquisar bem estes detalhes antes de tomar sua decisão final.

PS* Para quem não reside nas regiões sul/sudeste: Minha intenção não foi ofender ninguém. Estou apenas citando o fato de que devido a diversos fatores (entre eles, descaso do governo) muitas regiões do país tem sim uma infra-estrutura muito defasada e esse é um ponto que deve ser levado em consideração por alguém que planeja mudar de residência.

(…)

Rafael Ibraim
Oracle Database SQL Expert
ibraim...@gmail.com


Destaquei em negrito os trechos que deixam mais evidente o preconceito social e político do alienado, que aliás foi o único pomposo a colocar uma assinatura como expert Oracle.

O mais bonito dessa história toda foi a resposta de Alex Queiroz:
Apesar das pretensões separatistas da parcela supremacista branca das populações do Sul e Sudeste, o Brasil ainda é um único país. Achei então interessante o seu uso das palavras «desvio» e «nosso dinheiro», dado que uma vez que impostos federais são usados o governo federal pode usá-los onde bem entender. E só sendo um administrador muito burro para não usar o dinheiro onde ele é mais necessário, no caso do Brasil, fora do eixo Sul-Sudeste.

--
-alex
http://www.artisancoder.com/


Bem colocado.

[]’s
Cacilhας, La Batalema

2009-10-03

IDEs em ambiente GNU/Linux – RAD

Poliedro Este é o último de uma série de três artigos sobre ambientes de programação:

  1. Editores de texto
  2. IDEs focadas em projeto
  3. RAD



RAD


RAD ou desenvolvimento rápido de aplicações é o nome ou qualidade associado a qualquer ferramenta que proporcione facilidades para desenvolver aplicações rapidamente, geralmente com suporte a construção visual de objetos.

Algumas linguagens de programação e scripting já são consideradas RAD por si só, como Python, Ruby e Lua, entre outras.

Squeak


Squeak é uma máquina virtual e ambiente gráfico de RAD para Smalltalk, filho mais fiel do antigo Smalltalk-80 de Palo Alto.

É ao mesmo tempo máquina virtual para a execução de aplicações gráficas e IDE para programação. Em ambiente Squeak você utiliza basicamente três utilitários:
  • System Browser para editar as classes
  • Workspace para experimentação e execução
  • Transcript para exibição de resultados (STDOUT)


A aplicação mais conhecida usando Squeak é o XO do projeto OLPC.

Cincom VisualWorks


Outra ferramenta similar ao Squeak, porém proprietária, é o Cincom VisualWorks.

Também é uma máquina virtual e ambiente visual de programação e execução de aplicações, mas em seu caso as janelas são integradas ao gerenciados de janelas em execução.

Kylix


Kylix é o ambiente da Borland para a linguagem de programação Object Pascal.

Seu objetivo é oferecer uma alternativa em ambiente GNU/Linux para os usuários de Delphi (exclusivo de plataformas Windows).

A Borland restringiu o uso do Kylix, porém em compensação liberou uma versão aberta, o Open Kylix.

Gambas


Gambas é mais uma sigla recursiva: «Gambas Almost Means BASic».

É um IDE para desenvolvimento em Structured BASIC similar – mas não igual – ao Visual Basic da Microsoft.

É um de meus IDEs favoritos.

HBasic IDE


HBasic é uma tentativa de suportar códigos criados para Visual Basic no GNU/Linux.

Quem está acostumado ao VB vai se sentir bastante confortável no HBasic.

Sua GUI é baseada em Qt e suficientemente similar à do Visual Basic Express. Seus componentes e sua implementação própria do Structured BASIC também são confortavelmente próximos aos do VB.

Visual Tcl


Alguém também já ficou muito feliz em ver como é simples desenvolver aplicações gráficas utilizando Tcl/Tk?… E também estranhou muito sua sintaxe peculiar?

Visual Tcl é um ambiente visual de programação baseado em Tcl/Tk muito parecido com Delphi e que facilita bastante o uso de Tcl/Tk, essa linguagem com características tão próprias.

Gorm


Gorm, Graphical Object Relationship Modeller, é um ambiente de modelagem visual de objetos, classes e janelas muito superior e mais completo do que qualquer outro. É uma versão livre do Interface Builder da NeXT, atualmente propriedade da Apple.

Gorm é projetado para trabalhar associado ao ProjectCenter, assim como o Interface Builder trabalha associado ao Project Builder, e trabalha exclusivamente com Objective C e a biblioteca GNUstep.

É um de meus IDEs favoritos.

Glade


Glade é uma ferramenta RAD para desenho de janelas Gtk+ via interface gráfica, gerando como resultado um arquivo XML passível de ser processado por qualquer linguagem que tenha acesso ao GtkBuilder da biblioteca GLib.

Qt Designer


Qt Designer é um ambiente muito similar ao Glade, só que para biblioteca Qt.

É idealizado para trabalhar junto a aplicações como KDevelop, mas pode ser usado em associação a qualquer plataforma que possua acesso a Qt e um interpretador de arquivos UI.

É outro de meus IDEs favoritos.


**

Espero que esta série de artigos seja útil a quem procura por um novo ambiente de programação em plataforma GNU/Linux (ou até mesmo em outras).

[]'s
Cacilhas, La Batalema

IDEs em ambiente GNU/Linux – Editores de texto

Poliedro Este artigo é o primeiro de uma série de três artigos sobre ambientes de programação:

  1. Editores de texto
  2. IDEs focadas em projeto
  3. RAD


É comum os programadores se sentirem presos sempre às mesmas IDEs, como Visual Studio, NetBeans, Eclipse, JBuilder e até Delphi por não conhecerem ou por medo de outros ambientes de desenvolvimento.

A coisa piora quando o programador por um motivo qualquer começa a usar GNU/Linux e não encontra sua IDE preferida ou descobre que o Eclipse roda incomodamente mais travado que no Windows – pelo menos o JBuilder e o NetBeans rodam tão pesados quando no Windows. =D

Meu objetivo neste artigo é mostrar algumas alternativas do mais simples e leve à mais completa (e pesada) IDE.

Observação: a maioria dos (se não todos) ambientes citados aqui tem versões para Windows e Mac OS X.


EDITORES DE TEXTO


Desde os tempos mais remotos os editores de texto são a forma mais simples para o desenvolvimento de software.

Eles se tornaram práticos a partir da invenção da edição visual e mais práticos ainda com outras facilidades interessantes, como realce de sintaxe e autocompleção.

Vim


Vim contrabalancea recursos oferecidos e consumo de recursos do sistema e dá de dez em qualquer IDE, principalmente se você usar gvim, uma interface Gtk+ para Vim.

Porém seu paradigma de uso é muito diferente dos demais editores: Vim (Vi IMproved) é um clone melhorado do VI (Visual Interface), uma interface visual para o editor ex do Unix. Portanto os comandos de edição do Vim são similares aos do ex.

Vim, assim como VI, possui três modos de uso:
  • Modo de comando: é possível executar comandos de edição
  • Modo de edição: é possível editar diretamente o texto
  • Modo de visualização: usado para seleção avançada


Os comandos do Vim não são exatamente o que se pode chamar de intuitivos. Por exemplo, para saltar um arquivo o comando é :w e para sair do Vim :q – se houver edições não salvas, é preciso forçar o comando com exclamação: :q!.

GNU Emacs


Emacs (Editor Macros) é o culpado pelo Software Livre e o Projeto GNU. =D

Emacs é um ambiente de programação fortemente voltado para eLisp, apesar de também com suporte a outras linguagens.

Seus comandos também não são exatamente mnemónicos… para salvar um arquivo pressione C-x C-s (Ctrl+X depois Ctrl+S) e para sair C-x C-c. M-x (Esc depois X ou Alt+X) entra em modo de comando.

Além de editor de texto, Emacs é também um ambiente de execução de aplicações eLisp, havendo diversas interessantes, até mesmo leitor de correio eletrónico e navegador web. Como usuário de Vim, sou obrigado a comentar que Emacs é uma ótima plataforma operacional, apenas carece de um bom editor de texto. =D

[]'s
Cacilhas, La Batalema

2008-09-07

Regressão linear

Poliedro Já faz algum tempo que escrevi um artigo no Kodumaro sobre regressão linear.

O Eduardo Willians reclamou que não foi possível entender o problema – com razão, pois realmente não entrei em detalhes sobre regressão linear em si, já que o foco do artigo era a implementação do algoritmo.

Daí resolvi tentar explicar melhor o que é regressão linear aqui.

Em estatística, quando temos um grupo de dados cartesianos – por exemplo, o consumo de CPU ao longo de um período de tempo –, há ferramentas para se obter os dados que faltam, sejam dentro do mesmo período ou fora.

As técnicas para se obter dados intermediários que não constam no conjunto de dados são conhecidas por interpolação e as técnicas para se obter dados fora do período considerado são chamadas extrapolação.

Os algoritmos mais comuns de interpolação são polinómio de Newton, polinómio de Lagrange e método de Vandermonde.

Os algoritmos usados para extrapolação são as regressões lineares, que consistem em identificar um padrão evolutivo linear dos dados, ou seja representados por uma reta – função do primeiro grau. Essa função do primeiro grau é chamada de regressão simples.

É claro que eventualmente os dados podem não evoluir de forma linear, mas mesmo nesses casos usamos outras técnicas de regressão linear onde um dos eixos é achatado por meio de potenciação, logaritmização ou exponenciação, então temos regressão por potência, regressão logarítmica e regressão exponencial.

No entanto esses algoritmos também são reduzidos à regressão simples – vamos nos limitar a ela.

Resumindo o que foi dito até aqui, regressão linear consiste em representar um conjunto de dados cartesianos (xi, yi) da seguinte forma:
yi = a + bxi + Ei

Onde:

  • yi – ordenada, por ex., percentagem de uso da CPU;
  • xi – abscissa, por ex., data/hora da coleta de percentagem;
  • α – interceção, valor calculado;
  • β – inclinação, valor calculado;
  • εi – erro ou desvio, valor a ser aplicada à ordenada estimada para corrigi-la ao valor correto.


Ou seja, o desvio é a diferença entre a ordenada estimada (calculada) e o valor real:
Ei = yi -(a + bxi)

A ideia por traz da regressão linear é bastante simples: encontrar os valores para α e β tais que o somatório dos quadrados dos desvios para os valores conhecidos seja o menor possível.

A forma mais didática para se calcular isso é usando o produto de matrizes, mais especificamente, sistema subdeterminado de equações normais. Nesse sistema, criamos uma matriz normal 2×2, um vetor de coeficientes de ajuste como (α β) e a matriz direita padrão.

No final das contas temos isso:
--

Na Wikipédia, no subtópico Cálculo dos fatores α e β estão os cálculos.

Obviamente, usando a regressão linear para extrapolação, só é possível estimar valores, não os prever realmente.

[]'s
Cacilhas, La Batalema

2008-05-03

Arquivo vs Objeto

Smalltalk Outro dia li em um blog – infelizmente não lembro onde – uma falácia interessante, fruto de desinformação e manipulação.

O autor fazia uma comparação entre Smalltalk e Java.

Nessa comparação o autor apresentava argumentos a favor de Java e contra Smalltalk… na verdade era um único argumento repetido umas poucas vezes de formas diferentes.

O argumento dizia que Java é superior a Smalltalk porque é baseado em arquivos e Smalltalk em objetos: em teoria, arquivos seriam superiores porque permite que o desenvolvedor veja os códigos fonte das bibliotecas Java, enquanto que os objetos de Smalltalk não ofereceriam uma forma de visualizar o código.

Pura desinformação.

Acho que a referência de bibliotecas Java do autor deve ser o projeto Apache, que oferece os códigos fontes, pois até a pouco tempo atrás nenhuma biblioteca da SUN Microsystems oferecia acesso aos códigos.

Aliás, apesar de haver algumas boas bibliotecas de código aberto, quase todas as bibliotecas oferecidas para Java são proprietárias, oferecidas em formato JAR, semelhante ao formato AR, contendo bytecodes (binários) para JVM.

Realmente os fontes para Visual Works são fechados, mas essa é uma ferramenta proprietária da Cincom. Outras implementações de Smalltalk que vi oferecem os fontes em anexo: GNU Smalltalk oferece os fontes em arquivos texto em $PREFIX/share/smaltalk e Squeak oferece acesso aos fontes através do System Browser.

Posso concluir duas coisas: ¹o autor deve ser forte defensor de Java – ou está entoxicado por algum evangelizador javista – e ²isso o levou a tirar conclusões sobre Smalltalk em observação apenas superficial.

Então volto a alertar o leitor: muito cuidado ao ler artigos sobre linguagens, principalmente aqueles que defendem linguagens da moda ou que já estiveram na moda, linguagens com forte marketing.

Geralmente esse tipo de texto é tendencioso, ou propositalmente, porque o autor é um evangelista, propagandista, ou porque o autor está evangelizado.

[]'s
Cacilhas, La Batalema

2008-04-27

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 no Kodumaro.

2008-02-03

Ambiente personalizado no interpretador Python

Este artigo é só uma dica rápida…

Muitas vezes é interessante ter um ambiente um pouco mais personalizado no interpretador Python sem precisar ficar reconfigurando-o a cada carga.

Por exemplo, eu gosto das seguintes configurações iniciais:

from __future__ import division
from __future__ import with_statement
from types import *
importe re
importe os, sys

__metaclass__ = type


A saída é salvar essas configurações num arquivo .pythonrc.py, por exemplo no homedir.

Mas apenas isso não é suficiente. É preciso que o interpretador Python saiba que precisa carregar essas configurações a cada início de interpretador. Para tanto, é preciso ajustar a variável PYTHONSTARTUP.

Em bash, coloco essa variável em meu ~/.bash_profile:
export PYTHONSTARTUP=~/.pythonrc.py


E pronto! A cada execução do interpretador essas configurações serão carregadas. Por exemplo:
bash$ python
Python 2.5.1 (r251:54863, May 4 2007, 16:52:23)
[GCC 4.1.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 2/3
0.66666666666666663
>>>


Sem essas configurações, o retorno para 2/3 seria 0 – inteiro, não float.

[]'s
Cacilhas, La Batalema

2007-06-04

Um framework faça-você-mesmo

Poliedro Este artigo é uma tradução livre de um artigo do Python Paste. Você pode encontrar o original aqui.

Ah! Desculpem-me se quebrei alguns códigos, mas senão eles iam ficar «comidos». =/

Sumário


Author: Ian Bicking <mailto:ian@colorstudy.com>
Revisão: 5488
Data: 2006-07-25 17:22:52 -0500 (Ter, 25 Jul 2006)
Tradução: Rodrigo Cacilhas
Data: 2007-07-04



Introdução e público


Este pequeno tutorial pretende ensiná-lo um pouco sobre WSGI e é um exemplo de um pouco da arquitetura que Paste tem permitido e encoraja.

Esta não é uma introdução a tudo sobre Paste – de fato apenas serão usadas e explicadas algumas partes. Também não pretente encorajar todo mundo a sair criando seus próprios frameworks (no entanto honestamente eu não me importaria). A meta é que quando você tiver terminado de ler este artigo você se sinta mais a vontade com frameworks que usem esta arquitetura e um pouco mais seguro por entender o funcionamento interno por trás dos panos.

O que é WSGI?


Em sua forma mais simples WSGI é uma interface entre servidores web e aplicações web. Os mecanismos de WSGI serão explicados abaixo, mas um visão de mais alto nível é dizer que WSGI permite que código passe através de requisições web de forma razoavelmente formal. Mas há mais! WSGI é mais que apenas HTTP. Pode parecer que seja pouco mais que HTTP, mas um pequeno ponto é importante:
  • Você passa ao redor de um ambiente tipo CGI, que significa que dados como REMOTE_USER (o usuário autenticado) podem ser passados em segurança.
  • Um ambiente tipo CGI pode ser passado com mais contexto – especificamente em vez de apenas um caminho você tem dois: SCRIPT_NAME (como começamos aqui) e PATH_INFO (o que deixaremos).
  • Você pode – e muitas vezes deve – colocar suas extensões dentro do ambiente WSGI. Isso permite rechamadas, informações extras, objetos Python arbitrários, ou o que você quiser. Essas são coisas que você não poderia colocar em cabeçalhos HTTP personalizados.


Isso significa que WSGI pode ser usado não apenas entre um servidor web e uma aplicação, mas em todos os níveis de comunicação. Isso permite que aplicações web se tornem mais do que bibliotecas – bem encapsulado, mas ainda assim ricamente reusável.

Escrevendo uma aplicação WSGI


A primeira parte trata de como usar WSGI da forma mais básica. Você pode ler a especificação, mas farei um sumário bastante breve:
  • Você escreverá uma aplicação WSGI. Esse é um objeto que responde a requisições. Uma aplicação é apenas um objeto chamável (como uma função) que recebe dois argumentos: environ (ambiente) e start_response (pré-resposta).
  • O ambiente se parece bastante com um ambiente CGI, com chaves como REQUEST_METHOD, HTTP_HOST, etc.
  • O ambiente também possui algumas chaves especiais como wsgi.input (o fluxo de entrada, como o corpo de uma requisição POST).
  • start_response é uma função que inicia a resposta – você fornece estado e cabeçalhos aqui.
  • Por último a aplicação retorna um reiterador com a resposta corpo (geralmente é apenas uma lista de strings ou apenas uma lista contendo uma string com o corpo inteiro).


Então aqui está uma aplicação simples:
def app(environ, start_response):
start_response("200 OK", [
("Content-Type", "text/plain")
])
return ["Ola Mundo!"]


Bem… que sem graça. Certo, você pode imaginar o que ele faz, mas não pode simplesmente chamá-lo do navegador.

Há outras formas mais limpas de fazer isso, mas este tutorial não trata de «limpeza», mas de «clareza». Então apenas adicione ao fim do arquivo:
if __name__ == "__main__":
from paste import httpserver
httpserver.serve(app, host="127.0.0.1", port=8080)


Agora acesse http://127.0.0.1:8080/ e você poderá ver sua nova aplicação. Se quiser entender como um servidor WSGI funciona, recomendo ver CGI WSGI server na especificação WSGI.

Uma aplicação interativa


A última aplicação não foi muito interessante. Vamos ao menos torná-la interativa. Para fazer isso vamos dar-lhe um formulário e então analisar os camos do formulário:
from paste.request import parse_formvars

def app(environ, start_response):
fields = parse_fromvars(environ)
start_response("200 OK", [
("Content-Type", "text/html")
])
if environ["REQUEST_METHOD"] == "POST":
return ["Ola, ", fields["name"], "!"]
else:
return [
'<form method="POST">Nome:',
'<input type="text" name="name" />',
'<input type="submit" />:</form>'
]


A função parse_fromvars apenas pega o ambiente WSGI e chama o módulo cgi (a classe FieldStorage) e o transforma em um multidicionário.

Agora para um framework


Agora isso parece um pouco bruto. Apesar de tudo, estamos testando coisas como REQUEST_METHOD para manipular mais do que uma coisa e não está claro como você pode ter mais do que uma página.

Nós queremos criar um framework, que é apenas um tipo de aplicação genérica. Neste tutorial implementaremos um publicador de objeto, que é algo que você pode ter visto no Zope, Quixote ou CherryPy.

Publicação de objeto


Num publicador de objeto Python típico você traduz / para .. Então /articles/view?id=5 se torna root.articles.view(id=5). Temos de iniciar com algum objeto raiz, claro, que nós passamos…
class ObjectPublisher(object):
def __init__(self, root):
self.root = root

def __call__(self, environ, start_response):


O método __call__() foi sobrescrito para tornar instâncias de ObjectPublisher objetos chamáveis, exatamente como uma função, e exatamente como uma aplicação WSGI. Agora tudo o que precisamos fazer é traduzir esse environ para dentro da coisa que estamos publicando, então chamá-la, depois formatar a resposta para WSGI.

O caminho


WSGI coloca o caminho requisitado em duas variáveis: SCRIPT_NAME e PATH_INFO.SCRIPT_NAME. É tudo que usaremos. PATH_INFO é sempre deixado de lado – é a parte que o framework deveria estar usando para encontrar o objeto. Se você colocar os dois juntos de volta, você tem o caminho completo para chegar onde estamos agora mesmo; isso é muito útil para gerar URLs corretas e termos certeza de preservar.

Então aqui está como é possível implementar __call__():
def __call__(self, environ, start_response):
fields = parse_formvars(environ)
obj = self.find_object(self.root, environ)
response_body = obj(**fields.mixed())
start_response("200 OK", [
("Content-Type", "text/html")
])
return [response_body]

def find_object(self, obj, eviron):
path_info = environ.get("PATH_INFO", "")
if not path_info or path_info = "/":
# Chegamos!
return obj
# PATH_INFO começa sempre com a /, assim vamos nos
# livrar disso:
path_info = path_info.strip("/")
# Então vamos quebrar o caminho no pedaço seguinte,
# e tudo depois dele:
parts = path_info.split("/", 1)
next = parts[0]
if len(parts) == 1:
rest = ""
else:
rest = "/" + parts[1]
# Esconda atributos e métodos privados:
assert not next.startwith("_")
# Agora pegamos os atributos; getattr(a, "b")
# equivale a a.b...
next_obj = getattr(obj, next)
# Agora corrija SCRIPT_NAME e PATH_INFO...
environ["SCRIPT_NAME"] += "/" + next
environ["PATH_INFO"] = rest
# E agora analise a parte restante da URL...
return self.find_object(next_obj, environ)


E é isso, temos um framework.

Levando para um passeio


Agora vamos escrever uma pequena aplicação. Coloque essa classe ObjectPublisher no módulo objectpub:
from objectpub import ObjectPublisher

class Root(object):
# O método "index":
def __call__(self):
return """
<form action="welcome">
Nome: <input type="text" name="name" />
<input type="submit" />
</form>
"""

def welcome(self, name):
return "Ola, %s!" % name

app = ObjectPublisher(Root())

if __name__ == "__main__":
from paste import httpserver
httpserver.serve(app, host="127.0.0.1", port=8080)


Tudo certo, feito! Ops, espere. Há ainda algum grande recurso esquecido, por ex. como você ajusta cabeçalhos? E em vez de responder 404 Not Found em algum lugar, você apenas consegue um erro de atributo. Vamos corrigir essas coisas em uma próxima…

Dê-me mais!


Você notará que algumas coisas não estão certas. Mais especificamente, não há como ajustar os cabeçalhos de saída e a informação na requisição está um pouco ligeira.
# Este é apenas um objeto tipo dicionário que possui
# chaves insensíveis ao caso:
from paste.response import HeaderDict

class Request(object):
def __init__(self, environ):
self.environ = environ
self.fields = parse_formvars(environ)

class Response(object):
def __init__(self):
self.headers = HeaderDict(
{ "Content-Type": "text/html" }
)


Agora vou ensinar a você um pequeno truque. Não queremos mudar a assinatura dos métodos. Mas não podemos colocar os objetos de requisição e resposta em variáveis globais normais porque queremos estar preparados para multithreading e todas as threads veem as mesmas variáveis globais (mesmo se estiverem processando requisições diferentes).

Mas Python 2.4 introduz o conceito de «valores locais de thread». É um valor que apenas sua própria thread pode ver. Isso está no objeto threading.local. Quando você cria uma instância de local, qualquer atributo que você ajuste nesse objeto só pode ser visto pela thread onde você ajustou. Então Vamos anexar os objetos de requisição e resposta aqui.

Então vamos lembrar-nos de como a função __call__ se parecia:
class ObjectPublisher(object):


def __call__(self, environ, start_response):
fields = parse_formvars(environ)
obj = self.find_object(self.root, environ)
response_body = obj(**fields.mixed())
start_response("200 OK", [
("Content-Type", "text/html")
])
return [response_body]


Vamos atualizá-la:
import threading
webinfo = threading.local()

def __call__(self, environ, start_response):
webinfo.request = Request(environ)
webinfo.response = Response()
obj = self.find_object(self.root, environ)
response_body = obj(**webinfo.request.fields)
start_response(
"200 OK",
webinfo.response.headers.items()
)
return [response_body]


Agora em nosso método podemos fazer:
class Root:
def rss(self):
webinfo.response.headers["Content-Type"] = \
"text/xml"


Se fôssemos mais estravagantes faríamos coisas como cookies em nosso objeto. Mas não vamos fazer isso agora. Você tem um framework, fique feliz!

WSGI middleware


Middleware é onde as pessoas ficam um pouco intimidadas por WSGI e Paste.

O que é um middleware? É um software que serve de intermediário.

Então vamos escrever um. Vamos escrever um middleware de autenticação.

Vamos usar autenticação HTTP, que também é mistificada. Autenticação HTTP é bem simples:
  • Quando autenticação é requerida, devolvemos estado 404 Authentication Required com o cabeçalho WWW-Authenticate: Basic realm="Este campo"
  • O cliente envia de volta um cabeçalho Authorization: Basic encoded_info
  • O «encoded_info» é um versão base-64 de usuário:senha


Então como isso funciona? Bem, estamos escrevendo «middleware», o que significa que tipicamente passaremos a requisição para outra aplicação. Podemos mudar a requisição, ou mudar a resposta, mas neste caso às vezes não passaremos a requisição (como quando precisamos dar uma resposta 401).

Para dar um exemplo de middleware muito, muito simples, aqui está um que capitaliza a resposta:
class Capitalizer(object):
# Geralmente passamos a aplicação para ser
# envolvida pelo middleware:
def __init__(self, wrap_app):
self.wrap_app = wrap_app

def __call__(self, environ, start_response):
# Chamamos a aplicação que estamos envolvendo
# com os mesmos argumentos que recebemos...
response_iter = self.wrap_app(
environ,
start_response
)
# Então alteramos a resposta...
response_string = ''.join.(response_iter)
return [response_string.upper()]


Tecnicamente isso não está muito correto, porque há dois jeitos de retornar o corpo de resposta, mas estamos escovando bits. paste.wsgilib.intercept_output é uma implementação um tanto mais complexa disso.

Então aqui está algum código que faz algo mais útil, autenticação:
class AuthMiddleware(object):
def __init__(self, wrap_app):
self.wrap_app = wrap_app

def __call__(self, environ, start_response):
if not self.authorized(
environ.get("HTTP_AUTHORIZATION")
):
# Basicamente self.auth_required é uma
# aplicação WSGI que apenas sabe como
# responder com with 401...
return self.auth_required(
environ,
start_response
)
# Mas se tudo estiver certo, então passa tudo
# para a aplicação envolvida...
return self.wrap_app(environ, start_response)

def authorized(self, auth_header):
if not auth_header:
# Se eles não deram um cabeçalho, precisam
# autenticar-se...
return False
# .split(None, 1) significa quebrar em duas
# partes nos espaço:
auth_type, encoded_info = \
auth_header.split(None, 1)
assert auth_type.lower() == "basic"
unencoded_info = encoded_info.decode("base64")
username, password = \
unencoded_info.split(":", 1)
return self.check_password(username, password)

def check_password(self, username, password):
# Autenticação não muito segura...
return username == password

def auth_required(self, environ, start_response):
start_response(
"401 Authentication Required",
[
("Content-Type", "text/html"),
("WWW-Authenticate",
'Basic realm="this realm"')
]
)
return ["""
<html>
<head>
<title>Autenticação Requerida</title>
</head>
<body>
<h1>Autenticação Requerida</h1>
Se você não pode entrar, então fique fora.
</body>
</html:gt;"""]


Então como usar isso?
app = ObjectPublisher(Root())
wrapped_app = AuthMiddleware(app)

if __name__ == "__main__":
from paste import httpserver
httpserver.serve(
wrapped_app,
host="127.0.0.1", port=8080
)


Agora você tem um middleware!

Dê-me mais middleware!


É mesmo mais fácil de usar o middleware de outra pessoa do que fazer seu próprio, porque então você não precisa programar. Se você estava seguindo provavelmente, provavelmente encontrou algumas exceções e tem de dar uma olhada no console para ver os avisos de exceção. Vamos tornar um pouco mais simples e mostrar as exceções no navegador…
app = ObjectPublisher(Root())
wrapped_app = AuthMiddleware(app)
from paste.exceptions.errormiddleware \
import ErrorMiddleware
exc_wrapped_app = ErrorMiddleware(wrapped_app)


Fácil! Mas vamos tornar mais interessante…
app = ObjectPublisher(Root())
wrapped_app = AuthMiddleware(app)
from paste.evalexception import EvalException
exc_wrapped_app = EvalException(wrapped_app)


Então cause um erro agora. E acione os pequenos +. E digite qualquer coisa nas caixas.

Configuração


Agora que criamos seu framework e sua aplicação, você pode encontrar a usabilidade juntando algumas dessas partes um tanto cruas. Bem, se você não encontrar, alguém mais que usar sua aplicação e quiser instalá-la em um local diferente ou configurá-la de forma diferente não será bem sucedido.

Então queremos separar o ajuste da aplicação da configuração da aplicação.

E depois?


Fique ligado, falarei sobre configurações (usando Paste Deploy) mais tarde e espero dar uma curta introdução a empacotamente e plugins também. Quando acontecer, aviso em meu blog.

Ian Bicking





[]'s
Rodrigo Cacilhas

2007-04-24

Comparação de desempenho

Kodumaro
Estou estudando Haskell ao mesmo tempo em que me aperfeiçoo em Lua e Kepler.

Meu interesse em Haskell é usá-la como linguagem compilada, enquanto continuo usando Lua (e eventualmente Python) como linguagem geral.

Estava impressionado com a velocidade de Haskell em recursões, principalmente no cálculo de Fibonacci (que costumo usar para comparações de desempenho), resolvendo índices altíssimos em frações de segundo, enquanto a própria linguagem C demora para retornar algum resultado.

Foi então que me dei conta de que a implementação em Haskell de Fibonacci que eu estava usando aplicava memoização!

Resolvi refazer os códigos comparatórios usando memoização também nas outras linguagens.

Observação:


  1. Não refiz em Java porque não conheço a linguagem o suficiente para trabalhar com memoização (imagino que haja algum módulo pronto) e números grandes.
  2. Não refiz em C e C++ porque fiquei com preguiça de reescrever usando GNU MP.


Fiz os testes da seguinte forma: executei cinco vezes cada «programa» anotando seus tempos de execução; removi o maior e e o menor tempos; calculei a média geométrica.

Foi aí que tive uma surpresa agradável: Lua foi a segunda mais rápida!

Seguem as médias:
  • Haskell: 4,0ms
  • Lua: 21,7ms
  • [update 2007-05-02]Ruby: 42,0ms[/update]
  • Python: 58,0ms
  • Perl: 97,3ms


[update 2007-05-02]
Escrevi errado da primeira vez!

Havia colocado microssegundo (μs) em vez de milissegundo (ms). Minha máquina não é tão rápida assim. =P

Desculpem!
[/update]


Agora os códigos (retirei os comandos de saída para stdout para medir as velocidades):

Haskell


module Main where

import IO

fib = 1 : 1 : zipWith (+) fib (tail fib)

main = do
hSetBuffering stdin LineBuffering
let num = fib !! 1000
putStrLn (show num)


Lua


local fib
do
local memo = setmetatable(
{ ["0"] = 1, ["1"] = 1 },
{ __mode = "k" }
)

function fib(n)
if not memo["" .. n] then
memo["" .. n] = fib(n - 2) + fib(n - 1)
end
return memo["" .. n]
end
end

local num = fib(1000)
print(num)


[update 2007-05-02]
Ruby

def fib(n, memo={ 0 => 1, 1 => 1 })
if not memo.member? n
memo[n] = fib(n - 2, memo) + fib(n - 1, memo)
end
return memo[n]
end

num = fib(1000)
print(num)


Obrigado Fenrrir!
[/update]


Python


def fib(n, memo={ 0: 1, 1: 1 }):
if not n in memo:
memo[n] = fib(n - 2) + fib(n - 1)
return memo[n]

num = fib(1000)
print(num)


Perl


use Memoize;

sub fib {
my $n = shift;

if ($n < 2) {
return 1;
} else {
return fib($n - 2) + fib($n - 1);
}
}

memoize 'fib';

my $num = fib 1_000;
print "$num\n";

exit 0;



[]'s
Rodrigo Cacilhas

2007-04-12

Kodumaro

Kodumaro
Em respeito aos assinantes de RSS e à identidade das Reflexões de Monte Gasppa e Giulia C., não vou mais «ecoar» os artigos publicados no Kodumaro aqui.

Quem quiser continuar acompanhando os artigos do Kodumaro por aqui, basta seguir a lista na barra lateral, que é atualizada via RSS.

[]'s

2007-04-06

Alterando o comportamento de strings em Lua on-the-fly

Lua Um recurso legal de Lua é permitir a alteração do comportamento de strings «on-the-fly».

Por exemplo, strings em Lua não possuem métodos para «capitalizar» e «normalizar», mas podemos criar.

Por exemplo:

> var = "la batalema pitonisto"
> print(var:normalize())
stdin:1: attempt to call method 'normalize' (a nil value)
stack traceback:
stdin:1: in main chunk
[C]: ?


Pois é… não existe. Mas podemos criar!

Nem precisa reiniciar o interpetador. Vamos continuar daí e criar nosso normalize():
> function string:normalize()
>> local t = {}
>> local naocapitular = { "da", "das", "de", "do", "dos", "e" }
>> self:gsub("(%S+)", function (e)
>> e = e:lower()
>> local alterar, lig = true
>> for _, lig in ipairs(naocapitular) do
>> if e == lig then alterar = false end
>> end
>> if alterar then
>> e = e:sub(1, 1):upper() .. e:sub(2)
>> end
>> table.insert(t, e)
>> end)
>> return table.concat(t, " ")
>> end


Vamos analisar…

A tabela naocapitular contém uma lista dos elementos que não queremos capitular. Se quiser, você pode acrescentar outros termos de ligação, como "el", "von", "van", "and", "du", etc..

A chamada do método gsub() de self seleciona cada palavra ("(%S+)") e executa a função passada como segundo parâmetro para cada ocorrência.

A função transforma todas letras de cada palavra para minúsculas (e:lower()), depois corre um for para verificar se a palavra atual devem ou não ser capituladas.

Se a palavra deve ser capitulada, transforma a primeira letra em maiúscula (e:sub(1, 1):upper()), mantendo as demais (e:sub(2)).

Finalmente a palavra é inserida na tabela temporária.

Já no final de normalize(), o return retorna uma string, concatenando os elementos de t usando um espaço (" ") como separador.

Bem, feito isso, é só pegar o mesmo comando anterior:
> print(var:normalize())
La Batalema Pitonisto


Olha só! A string que já existia passou a ter o método normalize()!

Isso aconteceu devido à forma como Lua trata os objetos: metatabelas!

Toda string possui como metatabela uma tabela cuja chave __index aponta para o módulo string:
> print(getmetatable("").__index == string)
true


Então quando a função normalize() foi acrescentada ao módulo string, esta passou a ser método de todas as strings, mesmo as já criadas!

Com isso em mãos, as possibilidades são enormes. =)

[]'s

PS: Veja este artigo também no Kodumaro.

2007-04-02

Instalando Haskell no Slackware

haskell Se você é usuário de Slackware e, como eu, sofreu para tentar instalar o ghc sem sucesso, aqui segue o passo-a-passo para sair da miséria!

Estes procedimentos foram testados no Slackware 11.0.

Primeiro vamos baixar o maldito RPM. Se quiser procurar por outros pacotes, veja aqui.

Baixado o monstro, vamos convertê-lo em algo mais decente com rpm2tgz:

bash$ rpm2tgz ghc66-6.6-1.i386.rpm


Agora é possível manipular este pacote. Vamos descompactá-lo:
bash$ mkdir raiz
bash$ tar xzvf ghc66-6.6-1.i386.tgz -C raiz/


Pronto! Já podemos criar uma descrição do pacote:
bash$ cd raiz/
bash$ mkdir install/
bash$ vim install/slack-desc


Eu uso o Vim, mas use o editor que lhe convier. Escreva o seguinte conteúdo:
ghc: The Glasgow Haskell Compiler v. 6.6
ghc:
ghc: GHC is a state-of-the-art, open source, compiler and interactive
ghc: environment for the functional language Haskell.
ghc:
ghc: This package was generated by rpm2tgz
ghc:
ghc: http://haskell.org/ghc/
ghc:


Salve e já temos nossa apresentação! Agora vamos criar um instalador que publique as bibliotecas no sistema e crie alguns links simbólicos amigos do peito:
bash$ vim install/doinst.sh


O conteúdo do arquivo:
#!/bin/sh

sed -i '/\/ghc/ d' /etc/ld.so.conf
echo '/usr/lib/ghc-6.6' >> /etc/ld.so.conf

( cd /usr/bin/ ; rm -rf ghc )
( cd /usr/bin/ ; ln -sf ghc-6.6 ghc )
( cd /usr/bin/ ; rm -rf ghci )
( cd /usr/bin/ ; ln -sf ghci-6.6 ghci )

ldconfig


Não é necessário, mas gosto de ter este arquivo executável:
bash$ chmod +x install/doinst.sh


O pacote RPM tem umas maluquices, como chamar o diretório de documentação de ghc66-6.6/ (versão 6.6 da versão 6.6? Redundâncias de Fedora Core…). Vamos acertar isso:
bash$ mv usr/share/doc/ghc{66,}-6.6


Para terminar vamos criar e instalar o pacote!

Para evitar possíveis dores de cabeça, vamos fazer isso como superusuário:
bash$ su -l
bash# chown -R root:root .
bash# makepkg -c y -l y ../ghc-6.6-i386-1.tgz
bash# cd ../
bash# installpkg ghc-6.6-i386-1.tgz


E pronto! Já é possível executar ghci e testar os exemplos do Torcato.

Ah! Não esqueça de guardar bem o pacote (ghc-6.6-i386-1.tgz) e limpar a sujeira (ghc66-6.6-1.i386.rpm, ghc66-6.6-1.i386.tgz e raiz/) que deixamos para trás!

[]'s

PS: Veja este artigo também no Kodumaro.

2007-03-26

Usando SQL com Lua

Lua Já há bastante tempo existe em programação a ideia de separar os dados da lógica do programa e, quando queremos poder fazer consultas estruturadas, bancos de dados relacionais são ótimos.

Primeiro as consultas eram feitas usando um pré-processamento que lia códigos estranhos à linguagem inseridos entre marcações de início e fim, mais ou menos assim:

EXEC SQL
DECLARE CUR CURSOR FOR
SELECT * FROM cadastro
WHERE grupo = 1
END-EXEC.


Mas era necessário rodar o pré-compilador, que substituía esses trechos por códigos mais complexos, o que era no mínimo desconfortável.

Mais tarde pensaram em fazer diferente: módulos com funções que recebem strings representando os comandos SQL (Structured Query Language) e os executam, «escondendo» assim toda complexidade do acesso sem necessidade de uma pré-compilação.

Outras sintaxes para acesso, também abstraindo a complexidade, foram desenvolvidas, como SQLObject e SQLAlchemy, mas nenhuma tão simples e popular quanto a simples passagem de uma string como parâmetro de uma função.

Por exemplo, em Python, temos o módulo MySQLdb:
import MySQLdb as mysql

conn = mysql.connect(
host="localhost",
user="batalema",
password="sEnH4",
db="empresa"
)

conn.query("""
SELECT * FROM cadastro WHERE grupo = 1
""")
cur = conn.use_result()


A conexão deve ser fechada com conn.close(). Os resultados de uma consulta são lidos com um tipo especial de reiterador chamado cursor. Isso permite que tabelas de centenas (ou milhares) de linhas (tuplas) sejam tratadas com muito pouco uso de memória. Já escrevi alguns artigos sobre o assunto.

LuaSQL


Seguindo o exemplo de Python, PHP e outras linguagens, Lua também envia os comandos SQL por meio de strings como parâmetros de funções para uma conexão e percorre os resultados com um cursor.

O módulo de Lua para acesso a SQL é LuaSQL, que é parte do projeto Kepler, uma plataforma para desenvolvimento web usando Lua. Por isso é recomendável instalar tanto Lua quanto LuaSQL através da instalação completa de Kepler 1.1 – no momento em que este artigo foi escrito, só havia disponíveis snapshots (release-cadidates). Também é recomendável a instalação de todos os pacotes opcionais (--with-optional=lualogging,luasql,luaexpat,luazip,md5).

Podemos ver agora como fazer os acessos usando LuaSQL.

O módulo traz submódulos de acesso a diversos SGBDs diferentes: MySQL (luasql.mysql), Oracle (luasql.oci8), PostgreSQL (luasql.postgres), SQLite (luasql.sqlite) e MS SQL Server (via ODBC: luasql.odbc). Vamos usar o padrão, luasql.mysql.

Em LuaSQL, antes de conectar ao SGBD, é preciso criar um ambiente de conexão:
require "luasql.mysql"

local env = assert(luasql.mysql())


A partir do ambiente podemos iniciar a conexão:
local conn = assert(
env:connect(
"empresa",
"batalema",
"sEnH4",
"localhost"
)
)


A ordem dos parâmetros (para luasql.mysql e luasql.postgresql, para outros ambientes veja o manual) é:
  1. Fonte (nome da base de dados)
  2. Usuário
  3. Senha
  4. Servidor


Efetuada a conexão, podemos criar nosso cursor. Precisaremos ainda de uma tabela Lua para receber cada uma das linhas da tabela SQL, chamadas tuplas:
local cur = conn:execute [[
SELECT * FROM cadastro WHERE grupo = 1
]]
local t = {}


O cursor possui dois métodos interessantes, um é numrows(), que retorna o número de tuplas da seleção, outro é fetch(), que retorna a próxima tupla ou nil se estiver chegado ao final.

O método fetch() recebe dois parâmetros: ¹a tabela que receberá a tupla e ²uma string que indica como a tupla será interpretada pela tabela Lua.

Há duas opções para o 2º parâmetro:
  • "n": os registros serão recebidos como pares índice-valor e a tabela será uma tabela indexada;
  • "a": os registros serão recebidos como pares chave-valor e a tabela será uma tabela associativa.


Então, para listar os resultados podemos fazer algo bem simples:
while cur:fetch(t, "a") do
table.foreach(t, print)
end


Para finalizar precisamos fechar o cursor, a conexão e o ambiente:
cur:close()
conn:close()
env:close()


Outros comandos SQL


O comando SELECT retorna um cursor para a tabela retornada, mas outros comandos não retornam cursores ou tabelas.

Em vez disso os demais comandos retornam o número de tuplas afetadas.

Conclusão


Se alguém ficou decepcionado, desculpe-me a falta de complexidade… mas o módulo é simples mesmo. =P

Aliás, todos os módulos do projeto Kepler são simples.

Para um pouco mais de «complexidade» (hehehe), veja o manual.

[]'s

PS: Publicado também no Kodumaro.

2007-03-11

Números complexos em Lua II

Lua Este artigo foi publicado por mim originalmente em Reflexões de Monte Gasppa e Giulia C.. Esta é uma atualização para Lua 5.1.

Lua é uma poderosa linguagem de programação procedimental, orientada a objetos, de tipagem dinâmica, baseada em tabelas associativas e semântica extensível, projetada e implementada no Tecgraf, Grupo de Computação Gráfica da PUC-Rio, em 1993.

Foi projetada para ser uma linguagem de extensão, para que fosse possível que os usuários reconfigurassem aplicações sem necessidade de recompilação das aplicações.

Atualmente é a linguagem de script mais usada para programação de jogos (em segundo lugar está Python).

Uma curiosidade de Lua é não haver um módulo de suporte a números complexos. Vamos então implementar um.

Metatabelas


Em orientação a objetos, classe é um molde para a criação de objetos similares, chamados instâncias em relação à classe. Lua trabalha com um conceito ligeiramente diferente: metatabelas e metamétodos.

Em Lua tudo são tabelas, cujos elementos são quaisquer objetos de primeira ordem, inclusive funções (chamadas métodos ou metamétodos em classes) e outras tabelas.

Alguns métodos especiais, chamados metamétodos aritméticos, são usados para reagir a operações aritméticas. Há ainda os metamétodos comparativos – que reagem a operações de comparação – e os metamétodos de string.

Os metamétodos aritméticos, comparativos e de string são: __add() (adição), __sub() (subtração), __mul() (multiplicação), __div() (divisão), __pow() (potência), __unm() (inversão de sinal), __tostring() (conversão para string), __concat() (concatenação), __eq() (igualdade), __lt() (menor que) e __le() (menor ou igual).

Alguém pode perguntar «e quanto a ‘maior que’ e ‘maior ou igual’?». A resposta é simples, se a > b então b < a, capicci? A mesma idéia é para diferença (a ~= b é o mesmo que not a == b).

Está confuso até aqui? Vai clarear assim que começarmos a criar nossa metatabela. Vamos então à criação de nossa metatabela: primeiro usaremos o construtor de tabela ({}) para criar a metatabela com alguns valores default e em seguida criaremos o construtor próprio para números complexos:
local cmt = { real = 0, img = 1 }
cmt.__index = cmt
function cmt:new(o)
o = o or {}
return setmetatable(o, self)
end


Números complexos são formados por duas partes, uma real (ℜ) e outra imagem (ℑ), então criamos nossa metatabela assim.

A sintaxe function cmt:new(o) é um açúcar sintático para function cmt.new(self, o) e é usada para métodos.

O comando setmetatable(o, self) define que a metatabela de o será self (que representa mt) e o elemento __index informa de onde a tabela deve retirar os valores padrão (para elementos não definidos), e será a própria metatabela.

No entanto queremos ter alguma flexibilidade ao criar um número complexo:
  • e não for passado argumento, queremos que a função retorne j;
  • Se for passado um número (real), queremos retornar ele mesmo;
  • Se for passado um número complexo, queremos retornar uma cópia dele;
  • Se forem passados dois números (reais), queremos que o primeiro seja a parte real e que o segundo seja a imagem (se a imagem for zero, retorne somente a parte real).


Assim sendo, podemos criar a seguinte função:
function new(...)
if #{...} == 0 then
-- nenhum argumento retorna j
return cmt:new { real = 0, img = 1 }
elseif #{...} == 1 and type(select(1, ...)) == "number" then
-- um argumento: numero real
return select(1, ...)
elseif #{...} == 1 and getmetatable(select(1, ...)) == cmt then
-- um argumento: numero complexo
return cmt:new { real = select(1, ...).real, img = select(1, ...).img }
elseif #{...} == 2 and
type(select(1, ...)) == "number" and type(select(2, ...)) == "number" then
-- dois argumentos reais
if select(2, ...) == 0 then
return select(1, ...)
else
return cmt:new { real = select(1, ...), img = select(2, ...) }
end
else
error "parse error"
end
end


Mostrando nosso número complexo


O primeiro método que definiremos será para exibir nosso número complexo.

Sem este método, o comando abaixo retornaria assim:
lua> print(numero)
table: 0×80725e0


E queremos que, na verdade retorne algo do tipo:
lua> print(numero)
3 + 2j


Para tanto é preciso definir o método __tostring(). Mas não será tão fácil assim!

Imagine só: precisamos definir pelo menos oito casos diferentes:
  1. imagem = 0
  2. real = 0, imagem = 1
  3. real = 0, imagem = -1
  4. real ≠ 0, imagem = 1
  5. real ≠ 0, imagem = -1
  6. real = 0, imagem ≠ 0
  7. real ≠ 0, imagem > 0 e imagem ≠ 1
  8. real ≠ 0, imagem < 0 e imagem ≠ -1


Vamos então!
function cmt:__tostring()
local a, b = self.real, self.img
if b == 0 then
return tostring(a)
elseif b == 1 and a == 0 then
return "j"
elseif b == -1 and a == 0 then
return "-j"
elseif b == 1 and a ~= 0 then
return a .. " + j"
elseif b == -1 and a ~= 0 then
return a .. " - j"
elseif b ~= 0 and a == 0 then
return b .. "j"
elseif b > 0 and a ~= 0 then
return a .. " + " .. b .. "j"
elseif b < 0 and a ~= 0 then
return a .. " - " .. (-b) .. "j"
else
error "unexpected (a + bj) combination"
end
end


Uma funçãozinha útil


Para definir alguns parâmetros importantes precisamos definir o que acontece com o número quando tentamos invertê-lo (1 / (a + bj)).

A operação matemática é multiplicar a fração resultante por uma expressão equivalente a 1, como (a - bj) / (a - bj).

Fazendo esta continha simpática, obtemos real a / (a² + b²) e imagem -b / (a² + b²).

Vamos criar nossa função:
local function inv(v)
if getmetatable(v) ~= cmt then
return v ^ (-1)
else
local a, b, q = v.real, v.img
q = a ^ 2 + b ^ 2
return new(a / q, -b / q)
end
end


Nesta função, a primeira coisa que fizemos foi verificar se o argumento é um número complexo. Se não for, a função retorna um dividido pelo argumento. Se for um número complexo, realiza o cálculo citado.

Repare na linha:
local a, b, q = v.real, v.img


Neste comando, a, b e q são definidos como variáveis locais. a recebe v.real, b recebe v.img e q recebe nil.

Inversão de sinais


Se temos um número complexo b, queremos que -b retorne um número complexo com os sinais do real e da imagem invertidos:
function cmt:__unm()
return new(-self.real, -self.img)
end


Igualdade


Vamos verificar igualdade. Quando Lua verifica a == b, sendo a e b tabelas, na verdade está verificando se a e b são exatamente a mesma tabela, não se seus elementos são iguais. O quer queremos quando comparamos dois números complexos é se representam o mesmo valor, ou seja, se seus reais são iguais e se suas imagens também são.

Precisamos então criar um método para tratar isso:
function cmt:__eq(v)
if getmetatable(v) == cmt then
return self.real == v.real and self.img == v.img
else
return self.img == 0 and v == self.real
end
end


Operações binárias


Agora definiremos as operações binárias, ou seja, que necessitam de dois operandos: adição (+), subtração (-), multiplicação (*), divisão (/), potência (^) e concatenação (..).

Em todos os casos verificaremos se o segundo elemento da operação é também um número complexo ou não.

  • Adição

function cmt:__add(v)
local a1, b1, a2, b2, a3, b3 = self.real, self.img
if getmetatable(v) ~= cmt then
a2, b2 = v, 0
else
a2, b2 = v.real, v.img
end
a3, b3 = a1 + a2, b1 + b2
return new(a3, b3)
end


Na declaração das variáveis locais, a1 recebe self.real e b1 self.img. Todas as demais variáveis recebem nil.

  • Subtração (nada além de adição com sinal invertido)

function cmt:__sub(v)
return self + (-v)
end


  • Multiplicação (muito semelhante à adição)

function cmt:__mut(v)
local a1, b1, a2, b2, a3, b3 = self.real, self.img
if getmetatable(v) ~= cmt then
a2, b2 = v, 0
else
a2, b2 = v.real, v.img
end
a3, b3 = a1 * a2 – b1 * 2, a1 * b2 + a2 * b1
return new(a3, b3)
end


  • Divisão (divisão é a multiplicação onde o segundo termo é invertido)

function cmt:__div(v)
return self * inv(v)
end


  • Potência (aqui trataremos apenas expoentes inteiros, que não passam de multiplicações sucessivas)

function cmt:__pow(v)
if v == 0 then
-- expoente 0 retorna 1
return 1
elseif v == 1 then
-- expoente 1 retorna uma cópia de si mesmo
return new(self)
elseif v < 0 then
-- expoente negativo retorna inversão
return inv(self ^ (-v))
else
local aux, cont = new(self)
for cont = 2, v do
aux = self * aux
end
return aux
end
end


Repare a recursividade na linha:
return inv(self ^ (-v))


A potência chama novamente __pow() para self, mas desta vez com argumento -v.

  • Concatenação (fácil: retorna a contenação das strings!)

function cmt:__concat(v)
return tostring(self) .. tostring(v)
end


Vamos tornar isso tudo útil?


Até agora está tudo muito bonito, tratando números complexos e tudo mais… mas números complexos só são úteis se pudermos fazer duas coisas: ¹converter números reais em complexos quando tentamos extrair a raiz de um número negativo e ²converter números complexos para reais por meio das operações básicas.

Bem, a segunda coisa nosso módulo já faz, falta a primeira! Para tanto, vamos criar uma função de raiz quadrada segura, que retorne um número complexo quando a base for negativa:
function sqrt(v)
if type(v) ~= "number" then
error "value must be a number"
end
if v >= 0 then
return v ^ .5
else
return new(0, (-v) ^ .5)
end
end


Também será útil termos uma função que retorne verdadeiro ou falso para verificar se um valor é um número complexo:
function iscomplex(v)
return getmetatable(v) == cmt
end
j = new()


Finalizando


Para transformar isso tudo num pacote, salve todos os códigos num arquivo (pode ser complex.lua) e coloque na primeira linha do arquivo:
module("complex", package.seeall)


Vamos agora testar! Acesse o diretório onde está o arquivo complex.lua e execute o interpretador lua51. Execute os seguintes comandos e veja se funciona:
lua> require “complex”
lua> for c = -4, 7 do print(c, complex.j ^ c) end
-4 1
-3 j
-2 -1
-1 -j
0 1
1 j
2 -1
3 -j
4 1
5 j
6 -1
7 -j
lua> a = complex.sqrt(-9) + 2
lua> b = complex.new(3, 2)
lua> print(a, b)
2 + 3j 3 + 2j
lua> print(a + b)
5 + 5j
lua> print(a * b)
13j
lua> print(a / 2)
1 + 1.5j
lua> print(b ^ 2)
5 + 12j


Se tudo sair direitinho, parabéns! Acabou de fazer seu primeiro módulo de números complexos.

[]’s

PS: A primeira versão deste artigo foi escrita para Lua 5.0 e publicada aqui. Esta versão foi publicada pela primeira vez no Wordpress.com, no entanto tive problemas com a ferramenta deles.