O império contra-ataca…

Péssima piadinha no título. Sorry. Mas eu explico adiante.

O título é para referenciar um antigo artigo neste blog – “Witty” – Um webserver em C++ – onde se propunha:

…. Mas, já pensou se pudéssemos desenvolver nossas aplicações web em C++?

Pois é. Era Jan/2012 e acho que não sabíamos que o “Império”, a.k.a Google, já estava planejando “um contra-ataque” ao Javascript, iniciando em Out/2011, o desenvolvimento da linguagem: Dart. Não o “Vader”, é claro, mas aparentemente com muitos poderes.

Piada explicada – sem graça, é lógico – apresento uma solução à questão supracitada, proposta pelo Fred.

Descobri, esta linguagem hoje, quando buscava sistemas de padrões para caracteres ASCII, no site do ECMA . O ECMA, para quem não conhece é uma associação européia para elaborar e gerir padrões estilo ISO/ANSI.

O último documento de standart, é a especificação da linguagem. O que me deixou curioso foi o nome e em seguida o site da linguagem. Quando busquei no Google, encontrei um “pad” onde podemos rodar o código e ver o resultado ao lado em formato de consoles ou de saída HTML. Tem o PI-Montecarlo , o Solar, o Spirodraw, e outros.

Se Fred ficou impressionado com o Wintty, eu desta vez tive a mesma epifania com este site, por alguns motivos:

  • Gosto de usar scripts.
  • Ultimamente estou fazendo alguma coisa com o AWK (i.e. GAWK), por que se parece com “C”, é de um dos autores do C,  e é bom usar C (E no Gawk, dá até para usar o gdb, sério!)
  • Gosto de Python, mas sempre acho muito “verboso” e tenho sempre a sensação que “alguns chips estão desalinhados”, apesar do enorme poder do Python.
  • Gosto de resultados rápidos e facilidade de provas de conceito: nada mais imediato do que colocar o código e o resultado numa tela e apresentar.
  • Entre outras coisas, possui um SDK, possibilidade de compilar para Javascript, é mais performático (ver: c|net sobre Dart).
  • E por fim – como programo em C, raramente me sinto confortável, por muito tempo, em outro ambiente, sempre tô voltando.

Fica a dica:

150px-dart-logo

 

Hello, FreeBSD!

Ando bem satisfeito com o LMDE LinuxMint e sua estabilidade. Sempre prontinho e alinhado com as minhas necessidades de performance em um laptop vintage + um pequeno SSD (120Gb).

Esta máquina não esquenta mais nem me deixa esquentar, esperando por um novo pacote de atualizações que vem de 6 em 6 meses ou de 3 em 3 anos.

Hoje, eu retirei o tal SSD de dentro do laptop e coloquei-o no meu adaptador de usb e o sistema simplesmente iniciou normalmente sem nem me informar que o disco tinha mudado de interno para plugado.

Mas por que eu precisaria “tirar” o disco de dentro do laptop e colocá-lo na ponta de um fio, na porta usb?

FreeBSD é a resposta. Instalar o FreeBSD em outro HD.

Ouvi dizer que o FreeBSD é mais performático e resolvi pesquisar um pouco. Primeiro instalei numa máquina virtual (virtualbox), depois que vi rodando, animei a instalar num disco real pois começei a ler sobre ele descobri muitos pontos em comuns com outras distros de GNU/Linux que já usei, principalmente com a filosofia de liberação de releases do Debian: CURRENT, STABLE e TESTING.

A primeira surpresa foi a pergunta que me fiz: por que uso GNU/Linux? Em princípio porque eu usei o Solaris e antes e não tinha dinheiro para comprar um equipamento que rodasse Unix num 486, por volta de 95. E foi por isto que eu descobri o mundo do Free/Open Source. Mas me dei conta que achei o GNU/Linux e simplesmente parei de procurar.

Outra foi ao saber da diferença entre usuários de FreeBSD e usuários de GNU/Linux: os primeiros são oriundos do Unix tentando criar um Unix num PC e ou outros são oriundos do PC tentando criar um Unix.

Isto me fez perceber que, apesar de ter sempre lido e ouvido a história do Unix, sempre usei GNU/Linux. E nunca pus a mão na massa para persistir no Unix no meu PC. Aprendi muito e devo muito ao mundo GNU/Linux.

Mas, depois de ler este artigo notei que estava perdendo a Sala Vip desta festa.

O FreeBSD está na base de praticamente todos os unices para PCs, “incluindo” o próprio GNU/Linux, muito antes do GNU/Linux. Ora se o meu LinuxMint, que é baseado no estabilíssimo debian é tão bom, imaginei como seria a estabilidade do FreeBSD.

E aí começa o meu interesse neste sistema: estabilidade. Boa parte diste interesse vem de uma base única que segue sendo atualizada – sem os “frufrus” de atualizações fodásticas vistas diáriamente nos sites oficiais e fóruns.

Há também um sistema muito bom de arquivos: o ZFS. Que, dizem, ser mais performático e seguro do que o ext4. Será?

E tem o problema da GPL V3 do GCC. O FreeBSD está migrando para o LLVM pois a V3 restringe as liçencas a ponto de não poderem ser utilizadas em produtos comerciais (o que na minha opinião, reduz a liberdade), ao contrário da liçenca BSD que prima por três regras básicas para seu uso:

– Não proclame que você criou o código do FreeBSD
– Não processe o pessoal do FreeBSD caso ele não funcione ou corrompa algo
– Não remova ou modifique a licença original

Bem diferentes das diversas “restrições do GPL” que basicamente existe para que o software GNU nao seja comercializado, mas distribuído livremente.

Independente destas políticas (elas não me restringem, pois sequer as entendo direito) o que gosto é de me manter em linha com produtos com os quais possa trabalhar sem ter que ficar “comprando” tudo de novo à cada nova versão ou que me proíba de “vender” algo caso eu crie.

Infelizmente esta realidade de “não comprar novos produtos” foi, de certa forma inserida nos novos “linuces” que já vi, onde sempre estão, como no Windows, preocupados com atualizações, versões mais modernas em intervalos curtos de tempo, etc. E os desktops cada vez mais carregados e cheios de apps e firúlas, a.k.a. bells and whistles. Sendo assim sempre busco versões estáveis que me permitam usar em vez de ficar atualizando um sistema.

Outra diferença que me saltou aos olhos foi questão da distribuição centralizada de pacotes. No GNU/Linux – mesmo com a filosofia do Bazaar – estamos sempre dependentes de – Cathedrals – para ter conforto. No meu caso a catedral sempre foi o Debian! Nunca entendi o “trocentilhão” de distros proliferadas… Sempre um Ubuntu, Suse ou Redhat, estão no “centro” e porquê? Simples: todos nós dependemos de dinheiro e as grandes companhias estão por detrás destas distros, prevalecendo as que tem mais recursos. Isto é óbvio.

Então… Se o FreeBSD teve sua origem em uma, a AT&T, que não podia comercializar software, por isso delegou para as universidades, porque não entender que as demais companhias dão incentivos e “mantêm” estas pesquisas vivas até hoje?

A maior surpresa então, finalmente, foi perceber que eu estou usando – quando instalo o FreeBSD, basicamente o mesmo código da Apple, mais precisamente o que é usado no OS X que é onde se encontra o kernel e, sim, o GNU/Linux não é e nem nunca se proclamou como um sistema operacional, mas como um kernel. O sistema operacional se formou como produtos GNU, pois o sistema tem que ter ferramentas e utilitários, afinal ninguém quer um kernel só pelo kernel. Mas o FreeBSD tem também estas ferramentas e obviamente integrada ao kernel, e desenvolvida pelo mesmo grupo. Além de possibilitar o uso dos produtos GNU!

No GNU/Linux, o kernel é de um “cara”… O resto, vem de várias partes e que normalmente estão em conflito: isto se assemelha a tanger um bando de gatos e querer que cheguem a um lugar definido. O FreeBSD, também tem as brigas de cachorro grande, mas a comunidade parece-me alinhada, como na distro que uso, na verdade cultuo, o Debian. A coisa fica mais “certinha” quando há centralização. Me desculpe os bazares, mas neste caso, me sinto mais confortável dentro da catedral, longe da anarquia.

A mola mestra de uma disto ou sistema é o seu compilador. Até a versão 2 do GPL era amplamente usado pelo FreeBSD, e desde 2010 está sendo eliminado aos poucos em detrimento ao LLVM/CLANG (nem sabia que isto existia, até ontem) que me pareceu algo muito interessante. É um compilador que trabalha para gerar código intermediário para que este código seja compilado no computador final… (Cabe pesquisa aqui.)

Eu sei que dá trabalho e toma tempo compilar, mas a performance e estabilidade são os frutos nobres destes investimentos. Quando usei o Gentoo em 2004 eu percebi isto claramente, mas esbarrei no meu uso de tempo e falta de conhecimento. Hoje já tenho um bom GNU/Linux rodando e um monte de computadores velhos, loucos para serem úteis: resultado, acabei de compilar o meu xorg num velho Desktop Dell o que levou ceca de 3 horas. Zero erro!

Agora me sinto “voltando para casa”, para mais perto do “culto” ao Unix.  Depois de anos trabalhando, satisfeito com o GNU/Linux. E sim, vou manter o meu LMDE Linux Mint pois é maravilhoso e indispensável (por enquanto) como o Windows foi, para mim,  algum dia, mas vou me esforçar em buscar o mesmo conforto, a partir de agora, no FreeBSD.

Dá trabalho, muito trabalho revisar conceitos – mas depois de ler o manual e começar a ler o velho livro de Michael W. Lucas – Absolute FreeBSD, percebo que o meu conhecimento deve se concentrar no FreeBSD de agora em diante. Afinal, se você for fabricar comida para cachorro, saiba que sempre terá que provar seu produto.

A tentação do conforto

O meu problema (resolvido):

Python 2.7.9 (default, Mar  1 2015, 12:57:24)
[GCC 4.9.2] on linux2
Type "copyright", "credits" or "license()" for more information.
>>> a=range(10)
>>>  a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>  b=map(lambda x:x+3, a)
>>>  b
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
>>>  c=filter(lambda x:x%2,b)
>>>  c
[3, 5, 7, 9, 11]

Em 5 minutos eu criei esta coisa aí em cima:

  • um array a com 10 itens
  • um array b, resultado da soma de todos os elementos com 3
  • um array c, com todos os elementos impares

Daí eu pensei… Se eu quiser fazer o mesmo, usando C, como seria?

Observando que:

  • não poderia queria usar o printf, nem outra rotina de formatação de saída, mas apenas “vomitar” a saida no stdout, no mesmo formato do python
  • o array usado tem dimensão fixa, mas poderia ser de qualquer tamanho
  •  a regra de mapeamento podria ser qualquer outra, ao invés de apenas somar 3
  • o filtro idem

Parti pro ataque, e foi curioso ver algumas meticulosidades do C, repipocarem vivas na minha mente e no meu código:

  •  O itoa não é parte do C padrão, mas neste caso me seria útil. (Acho que aqui alguém também pensou assim)
  • A alocação dinâmica é mandatória, pois não sabemos o tamanho do array

E … depois de 2h: após ganhar um lindo segfault, DESISTI. Abri 2 cervejinhas e voltei pro meu livro de Python.

O máximo que eu pude fazer segue abaixo (usando printf no protótipo para depois eliminá-lo):

** Aviso: Nem tente compilar isto, pois tá tudo ERRADO! ***

#include <stdio.h>
#include <malloc.h>

void pr_int(int i);
void pr_arr(int **, int);
int **range(int start, int end);
void unrange(int **a,int start, int end);

int main(void)
{
  int **a;
  a = range(0,9);
  pr_arr(a, 10);
  unrange(a, 0, 9);
  return 0;
}

void unrange(int **a,int start, int end)
{
  int x;
  for (x =0; x < end; (start-end); x++)
    {
      free(*(a+x));
      break;
    }
  free(a);
}

int **range(start, end)
{
  int **a;
  int x;

  a = malloc((end-start)*sizeof(int));
  for (x=0; x < 10; x++)
    {
      *a = (int*) malloc(sizeof(int));
      *a[0] = x;
      a++;
    }
  pr_arr(a, 10);
  return &a;
}

void pr_arr(int **arr, int arrlen)
{
  int x;
  fputs("[",stdout);
  for (x=0; x < arrlen; x++)
    {
      pr_int(*(arr++)[0]);
      if (x < arrlen-1)
	{
	  fputs("," ,stdout);
	}
    }
  fputs("]\n",stdout);
}

void pr_int(int i)
{
  printf("%d", i);
  /* char str[12]; */
  /* itoa(i, str); */
  /* puts(str); */
}

Conclusão

  • Não pelo GTD… Aliás não use GTD!
  • Não é pelo amor ao python: sempre fui contra linguagens “macdonaldas”.
  • Não sou contra o C, aliás admiro.

É porque estou ficando velho, e assim sendo devo otimizar o meu tempo.

Posso não saber sobre os meandros matemáticos de um filtro ou um mapeamento de array, mas é perceptível que quando trabalhamos com dados, estamos trabalhando, essencialmente com listas de dados – e precisamos – de filters, maps, dictionaries, árvores, etc. – que são, precisamente, ferramentas adequadas para manipular números e suas listas – Unicode por exemplo, é uma lista ou tabela, como queiram. E então porque não termos algo bom e menos idiota que uma planilha eletrônica?  Esta ferramenta que cozinha o conceito  “tudo pronto e já”  no seu cérebro e o tolhe de ser “a little bit more logical”.

Somos humanos, gostamos de conforto e para termos conforto (felicidade) devemos aprender a usar (dor) os módulos modernos de felicidade, como:

  • Carros automáticos
  • Splits
  • Smartphones
  • E, porventura, linguagens de computação de mais alto nível.

Sem nos esquecermos de suas origens e de como eles foram concebidos… Mas não deveriámos ficar reinventado … Deviamos progredir com estes confortos.

A minha era de “woodstocker” ou “hell’s angels” da informática se foi. Já era. Nem meu telefone hoje em dia usa fio, para que se apegar a alguma “route 66” do MIT… Legal ler histórias, mas se observarmos os samurais, veremos que não existem em sua forma plena, mas sim em sua essência. Afinal, a despeito de Wolverines, Darth Vaders, Alices, Deadpools, et al – usarem  “katanas”, em geral, ninguém as usa regularmente, exceto para fins artísticos, culturais e esportivo. E se tentam usar sem ter a devida habilidade, eventualmente, causam estragos.

E vamos por aí aprendendo sem eliminar os caminhos que me trazem ao presente.

Depois que eu descobri que até o Brian Kernighan usou VB, “my hell has frozen” e me toquei que meus conceitos precisam ser muito bem revisados daqui por diante.

Unicode: isso ninguém nunca me disse…

Os fantasmas  wchar, utf-8, latin-1, et al Que volta e meia nos assombram já tiveram seus momentos nesse e em tantos outros blogs.

Estou brincando com ncurses (em python linux/windows) e vendo até onde o meu desespero de tentar codificar algo simples que possa rodar nos dois sistemas pode ir. ;-)

O caso é que me deparei, mais uma vez, com a questão dos utf-8. Os problemas surgem quando tentamos usar as bibliotecas “gringas” para escrever interfaces para usuários brasileiros. Atividade destilada de tentar fazer coisas úteis com esta montoeira de tecnologia. Básico: sempre caímos no básico. Na minha situação, o problema vem de uma confessada preguiça de estudar a fundo o assunto.

Não teve jeito… Tive que entender mais um pouco. Logo que começei a programar em python percebi que códigos não funcionavam se usássemos acentos. A solução: inserir uma meta tag no início do código

#! -*- coding: utf-8 -*- (Feio né ?! Mas no python 2.x é assim.)

Para se usar ‘,’ em vez de ponto decimal, usamos o locale no ponto onde queremos obter a tradução. (Mas na pressa, vai na mão: substitua um pelo outro na string com as funções nativas)

O que aprendi em python, depois de algumas cabeçadas é que considerarei daqui por diante em qualquer linguagem: usar unicode nessas situações.

CODIFICAÇÃO é um “conjunto de regras” que atribui VALORES NUMÉRICOS para cada caractere de texto.

ASCII

  • márcio = m\xe1rcio (representado com 6 bytes)
  • ASCII cada caractere tem 1 byte
  • ASCII só permite 128 caracteres
  • Letras acentuadas não podem ser codificadas com ASCII standard (duh!)
  • Em ASCII estendido, entretanto, criaram códigos acima de 128, para acomodar outras línguas além do inglês e gráficos em modo texto.
  • Logo o ‘á’ seria codificado com o número 0xe1, podendo variar se trocássemos a “codepage”, ou seja os números acima de 128

UTF-8

  • márcio = m\xc3\xa1rcio (representado com 7 bytes)
  • Isto é uma string de 7 bytes, 1 byte = 8 bits, 1 bit => 0/1
  • Logo este texto, utf-8, é uma string CODIFICADA (encoded) no formato UTF-8
  • Note que o ‘á’ necessita de 2 bytes para ser codificado
  • Outras codificações (i.e, outros conjuntos de regras) podem representar o’á’ usandonúmeros (a.k.a códigos) diferentes
  •  Os primeiros 128 caracteres de UTF-8 tem o mesmo codigo numérico da tabela ASCII.
  • Logo, UTF-8 é uma EXTENSÃO da tabela ASCII!

O problema: se texto funciona codificado, assim como sempre foi, por que usar o unicode?

  • Tratamento de linguagem além de inglês
  • Usar módulos de terceiros
  • Aceitar entrada de texto arbitrária. (csv, db, html, xml, etc)
  • márcio = m\u00e1rcio (len 6: não interessando com quantos bytes foi representado)

O que é o Unicode?

  • Unicode é um modo de representar texto SEM DEPENDER DE BYTES. Como é feito em UTF-8, ASCII, etc, ou seja, se ASCII, UTF-8, etc São “texto”, Unicode é “TEXTUAL”. Em menor, no Unicode TEXTO é o CONTEXTO, i.e. uma abstração para TEXTOS.
  • Um caractere unicode – chamado de Code Point – tem um NÚMERO único para cada caractere de cada linguagem
  • Incluso no Unicode, existem diversos formatos de transformação: Unicode Transformation Formats (UTF)
  • UTF-8 é um das codificações mais utilizados e 8 ali significa que números 8-bit são usados. Poderia ser 16 (UTF-16), 32 (UTF-32) etc.
  • Suporta a maioria das linguagems escritas atualmente
  • Define mais de 1 milhão de code points
  • Na prática existem limites mas na teoria, como números, que são conceitualmente diferentes de bytes, poderíamos ter infinitas representações usando números, bastaria ir ampliando a tabela.
  • Unicode é um conceito.
Letra Unicode Code Point
á \u00e1

Mas, na prática você tem que CODIFICAR em uma CODIFICAÇÃO existente, ou seja, traduzir para o código que seu sistema usa: UTF-8, latin-1, ascii, Jis, etc

Estranho, mas unicode deve ser TRANSFORMADO, quando os sistemas (legados) não trabalham com ele diretamente. No caso do python 2.x, é usada a codificação … ASCII!

O que ocorre é que quando tentamos “guardar” um caractere que “foge” dos 128 bytes da tabela “ASCII” obtemos um lindo erro:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe1 in position 2: ordinal not in range(128)

Que basicamente quer dizer que o codec unicode não consegue decifrar o código do ‘á’ usando a tabela ascii (interna), daí aquela “gambiarra” que mostrei no início ( #! -*- coding…)

Se o sistema usasse unicode – como é em python 3.x – não haveria necessidade dessas traduções pois o unicode é um conceito o invés de um “esquema” de tradução.

Tem um “maluco”, Ian Albert que compilou (e imprimiu) uma tabela gigantesca com todos os Code Points conhecidos (1.114.112 ao todo).

unichart-printed

Decodificando texto em unicode.

  • Note DECODIFICAR é traduzir o code point para o seu sistema de codificação
  • Python o faz “automágicamente”
  • A CODIFICAÇÃO padrão do python 2.x é ASCII
  • Mas esta “mágica” tem seus percalços e eventualmente geração a exceção que citei anteriormente. A do “codec”
  • Uma solução seria iniciar o módulo selecionando a tabela com “a gambiarra”, mas se fossémos rodar em um sistema “latin-1”, teríamos lindas “sopinhas de letras” na tela – Semelhante ao que o Fred citou neste artigo: ISO-8859-1? UTF-8? WINDOWS-1252?

A solução

Não tem uma solução simples e única

Temos sempre vários módulos que possuem sua própria codificação

Creio que este seja um problema que esteja ocorrendo em outras linguagens também, nunca testei, mas deduzi pois nunca entendi, de fato,  o que ocorria nestes casos. Partia para a porrada e “ajeitava” o resultado.

O sistema tem que traduzir para apresentar e “destraduzir” para armazenar.

A solução matadora seria usar todos os sitemas referenciando o unicode diretamente ( Na prática: inviável)

Para amenizar devemos então seguir os passos

1. Decodificar imeditamente, assim que encontramos a string
2. Escrever nossos códigos usando Unicode onde pudermos
3. Codificar mais tarde

O BOM… É “bom” mesmo?

Alguns formatos de arquivos usam o BOM (Byte Order Mark)

São bytes no inicio do arquivo que essencialmente querem dizer “Eu sou um UTF-8

  • Muito populares nos windozes
  • Podem ter 2, 3 ou 4 bytes

E servem para “adivinhar” a codificação do arquivo… Lógico que não dará para confiar sempre. Alguém poderia colocar ordem LSB, MSB ou fazer qualquer outra “caca” na geração dos arquivos e, como isto não é padronizado, mas sim uma “dica”, melhor ignorar.

Tipo do encoding html (Fred…) visto. Eu poderia colocar uma codificação no cabeçalho e escrever usando outra no corpo. Essas bobagens sempre ocorrem ao importar arquivos csv, planilha, dos, sqlite, firebird, etc

  • Na dúvida, “chute” UTF-8.

Conclusões

  • Unicode não é o mesmo que UTF-8.
  • O último é apenas um formato de codificação para o primeiro.
  • Se você estiver lendo codificados com UTF-8, você deve DECODIFICAR antes de usar.
  • Ao decodificar você decodifica a string codificada em UTF-8 para uma string Unicode (sim para algum código do “tabelão”)
  • Para codificar, você fazer o inverso: CODIFICA para a base que o seu sistema usa
  • Não há do que se envergonhar se não entendeu. Muitos usam regras pré definidas e aplicam, sem saber ou pensar no assunto. (Eu por exemplo)

Referências:

Tabela ASCII

Apresentação IMPORTANTE de onde partiu este poste. (Não deixe de assistir)

Stackoverflow: onde sanei a minha dúvida e me deu o link para o cerne deste POST.

Aqui você obtêm os detalhes e a imagem JPG do TABELÃO UNICODE.

 

MVC – Model View Controller

It’s just like an egg-cup, como disse David Upton em seu livro CodeIgniter for Rapid PHP Application Development, 2007 Packt Publishing.
its_an_egg_cup
Esta imagem ficou em minha mente e entendo que ela pode ser, e é, aplicada aos nossos desenvolvimentos com vantagens. O problema com ela é a dificuldade de se manter dentro do paradigma, ou seja, sem violar as regras de comunicação entre as camadas.

Mas como já disse, percebi que a coesão é muito boa, quando se usa. O próprio Codeigniter é um exemplo disto.

Nota: este artigo ainda está incompleto.

Refs:
MVC na Wikipedia

Programação Funcional

O qué isto?

Trata-se de um modo (paradigma) de programar que aborda o projeto de forma matemática e as funções passam a ser os agentes de transformação dos dados. De forma análoga às funções matemáticas que levam um determinado valor a outro domínio.

A coisa parece bem estranha, e até onde vi, não só parece mas é estranha de fato. Imagine uma função que não possa transformar os elementos externos à ela e que não deve “retornar” um valor , mas operar transformações sobre ele, de modo que ao voltar ao domínio original, o valor esteja intacto. Daí a pergunta: como fazer algo útil com isto ?

Alegam os defensores deste paradigma que quando uma função deve alterar os valores, são colocadas em outra categoria, inferior, que possuem a vil tarefa de se comunicar conosco, os imperfeitos humanos. Estas funções “baixas” são na realidade as que operam e modificam os valores, mas as tarefas de dizer o que será apontado pertencem às funções de primeira classe e de alta ordem.

Vamos combinar que isto parece regra de maçonaria… Por que, pra que, ninguém sabe, mas sabe-se que os trabalhos são feitos nesta esfera e o trabalho sujo fica relegado aos não iniciados.

Iniciando o meu estudo sobre o assunto

O meu encontro com o LISP, anteontem, foi meio confuso. Estava procurando uma solução para um problema recorrente com strings e acabei resolvendo com o recurso da recorrência. (sic)
Apesar de algumas críticas, na verdade ‘uma’ crítica recebida, não pretendo desanimar do meu objetivo em entender está confusão. Não vou ficar fazendo um monte de programinha teste (pois já fiz vários ontem) para saber que não dá para avançar com este assunto sem muito estudo.
Ok, tenho documentação farta aqui comigo. Inteligência e tempo, nem tanto. O que me interessa não é (ainda) a maestria, mas sair da minha completa ignorância sobre o assunto.

PF – Programação funcional

Pelo pouco contato que tive, percebi que a programação funcional, baseada no Cálculo Lambda, é a alma deste negócio de LISP e seus asseclas (Scheme, Haskell, Emacs-Lisp, floresta et.al.)

Mas estou apenas no início da minha pesquisa sobre este assunto, já que eu achei o conceito muito parecido com o paradigma M-V-C. Quando tentei criar algo usando paradigma M-V-C, eu me deparei com o seguinte problema: muitas camadas de funções eram necessárias para se levar o dado modificado ao usuário. Achei difícil fazer deste modo, mas vi que, com um pouco de trabalho realizado pelas funções, que se tornam coesas por excelência durante o processo, o conjunto obtido é bastente sólido e robusto, ou seja menos bugs.

Mas também notei que há dificuldade em se manter o paradigma ao pé da letra e acabamos pecando em algum ponto (ou mesmo desistindo) e voltando ao que os puristas chamam de programação imperativa, esta que nós mortais usamos.

Modo de programar: Funcional x Imperativo

Existem estes dois modos, antagônicos, de se programar. Vi isto no livro, confesso quem nem sabia, e ambos são agrupados em duas linhas de linguagens e obviamente tem distintos modos de se pensar no problema.
Ambos são da mesma época. No modo imperativo, destacam-se o Fortan, Pascal, C, sendo que o Fortran, surgiu pouco antes do LISP, em meados dos anos 50.

As linguagens imperativas ou orientadas a estados foram desenvolvida com a meta de se resolver problemas computacionais númericos, enquanto a pretensão de linguagens como LISP, funcionais, era (e ainda é) a de desenvolver algorítmos para manipulação de símbolos ou dados simbólicos a exemplo de listas, árvores, grafos etc.

A construção básica das linguagens imperativas é composta por comandos, os quais modificam o estado, por exemplo, via uma atribuição a=2 e pelas iterações tipo loop – for, while, do while etc. Desta maneira, as linguagens imperativas são poderosas no suporte de acesso aleatório ou randômico as estruturas de dados como os arrays, os quais são essenciais na computação numérica.

Nas linguagens puramente funcionais, entretanto, não existe a noção de estados ou mudanças de estado. Os conceitos básicos são:

  • aplicar uma função a um argumento – como na matemática, aplicada uma função a um valor, este é levado a outro domínio (não confundir com transformação, que seria uma alteração para outro estado). Ex. f(x) = x², a função leva, num plano cartesiano, o valor de x, no eixo das abcissas, para a sua potência quadrada no eixo das ordenadas. Veja que x não deixa de ser x, mas assume em y, uma nova dimensão, outro valor. IMHO isto é “muido doido”!
  • definição da função propriamente dita. Exemplo: f(x) = x²+1 ou recursivamente, f(x) = if x = 0 then 1 else x * f(x-1).

Também se nota que além de aplicar e definia funções, é necessário se ter as operações fundamentais sobre os tipos básicos – números naturais, booleanos, etc. – e as operações condicionais para as decisões nos casos (if, case, etc.). Além disto as linguagens funcionais fornecem meios para definição de tipos recursivos de dados, listando explicitamente seus construtores (consing é o termo usado). Exemplo: a definição de árvores binárias:

tree = empty() | mk_tree(tree, tree)

Tem o empty como sendo um construtor “zerário” sem descendentes enquanto mk_tree é um construtor binário que parte de duas árvores, t1 e t2 para construir uma nova árvore cujos descendentes esquerdo e direito são respectivamente t1 e t2. (Continua “muido doido isto”).

Daí se pode concluir que as linguagens funcionais suportam não somente definições recursivas mas também definições recursivas de “tipos de dados”. Sendo a grande vantagem aludida, sobre as linguagens imperativas, como o C ou Pascal onde tipos de dados recursivos precisam ser implementados por intermédio de ponteiros (e outras gambiarritas más), notáveis pela sua sensibilidade a más interpretações (tornam-se facilmente selvagens, quando são mal elaborados) e fonte garantida de bugs difíceis de ser exterminar.

Uma abordagem típica usada ao desenvolvermos programas imperativos é a criação de um fluxograma descrevendo visualmente (Aha! É daqui que vem os maléficos ‘Visuals’ et al) o comportamento dinâmico do programa. Logo se pode deduzir que a tarefa principal de um programa imperativo é organizar o caos, aka comportamentos dinâmicos complexos, o famigerado controle de fluxo.

Na programação funcional, por sua vez, o comportamento dinâmico do programa não precisa (sim eles odeiam loops, eu já vi isto) ser especificado explicitamente. Ao invés disto basta se definir a função a ser implementada. (Que beleza… e o bicho fica lá grudado olhando para mim sem fazer nada, uma lista e pronto). É claro que na prática estas funções definidas são justamente hierárquicas, i.e. baseadas numa cascata de funções pré definidas (me lembrei das carreiras de pedras de dominó). Daí o programa, o oposto de uma definição de função, (o vilão desta história, eu ja ví isto, pois ele lida com o trabalho sujo de fazer pelo menos uma transformação: a que dá o peteleco na primeira pedra), usualmente toma a forma de uma aplicação f(e1,…, en) e é “evaluated”, ou seja avaliado, pelo interpretador (putz num tem jeito de compilar esta merda depois? Ahhh! Em algumas implementações tem.). A atividade de programar em uma linguagem funcional consiste em definir funções (explicitamente ou recursivamente) sem se preocupar com os aspectos dinâmicos da execução, já que isto é tarefa do interpretador (java, ou melhor, jávi este papo antes…). Por fim, então devemos nos concentar no que e esquecer o como (que papo mais RH, gerencial este). Assim sendo quando se define as funções em programação funcional devemos grudar nas formas de definição (que melda é esta?) fornecidas pela linguagem e não lançar mão dos recurso ordinários da matemática corriqueira (pelo que entendi, fazer do jeito mais difícil, até que se torne fácil. Parece até filme oriental …. Mestre, por que não posso tomar atalhos?)

No andamento deste estudo vou continar traduzindo e comentando esta loucura, porque parece loucura este caminho zen, e investigando o por quê deste treco estar a tanto tempo no mercado e, apesar de não ver a luz do mercado, continuar existindo, pelo jeito com força total e avante.

O modelo e seus aspectos

Os aspectos centrais das lingagens funcionais, que devem ser investigados, em particular como se dá a sua interação, são

Modelo ---------- Interpretador
\ /
\ /
Lógica

ou


Semantica notacional ------------------ Semantica Operacional
\ /
\ Calculo de Verificação/

PCF – Programming Computable Functional

Primeiramente introduzimos a mais simples linguagem funcional – PCF – com os tipos básicos porém sem os tipos recursivos.

A semântica operacional do PCF será dada por uma indução definida pela relação de avaliação (aqui eu viajei completamente para fora da órbita)

E ↓ V

Especificando que expressões E são avaliadas com valore V ( onde V são expressões particulares que não podem ser mais avaliadas ) (no popular seria V expressões terminais?). Por exemplo se E ↓ V e E é um termo fechado do tipo nat de números naturais, então V será uma expressão da forma n, i.e. uma expressão canônica para o numero natural n (usualmente chamado de numeral)

Este último parágrafo e mais um monte de notações descritas na tese original me afastaram do objetivo, acabei procurando letrinhas matemáticas para compor as fórmulas e isto inviabiliza o resto da leitura da tese, que apesar de interessante, é pouco prática.

Buscando outra referência para estudo… Ok, encontrei a Bíblia deste assunto.

A execução de código em LISP é chamada de “evaluation” (valoração ou avaliação) pois a parte sendo executada normalmente resulta em um objeto de daods chamado de “value” (valor) produzido pelo código. O símbolo => (agora a seta deitou…) é usada em exemplos para indicar que houve “valoração”. Por exemplo;

(+ 4 5) => 9

Já o símblo -> é usado em exemplos para indicar uma expansão de macro. Por exemplo:

(push x v) -> (setf v (cons x v))

O que no fim das contas quer dizer que as duas formas de código executam a mesma coisa; a segunda parte do código é a definição do que a primeira faz. (Parece com o #define do C)

O símbolo ≡ (aqui entra outro daqueles) é usado em exemplos para indicar equivalência de código, assim

(gcd x (gcd y z)) ≡ (gcd (gcd x y) z)

Que foca mais o “efeito” do que na substituição literal, portanto o “efeito” da valoração de (gcd x (gcd y z)) é equivalente ao efeito da valoração de (gcd (gcd x y) z) ( … santa ambiguidade, Batman).

Scheme
O common lisp está para o schema assim como o c++ está para o c.

Schema parece ser bem mais simples do que o common lisp. Mais um livro on-line que dsimistificou algumas dúvidas.

S-expessions: todos os tipos de dados podem ser reunidos em um único e abrangente tipo de dados chamado de s-expression (s vem de símbolo, e não de sigma como eu pensei). Daí:
42, #\c,
(1 . 2)
#(a b c)
“Hello”
(quote xyz)
(string->number “16”)
(begin (display “Hello, World!”) (newline))
são todos s-expressions.

Form: os programas em lisp são s-expressions, pois todos os programas são dados. Portanto um simples caracter do conjunto de dados #\c é um programa ou como se chamam (e eu não tinha sacado) um form (isto deve vir de fórmula, e não de formulário como eu tinha pensado) sendo portanto, o termo form geralmente mais utilizado no lugar de programa.

Nota: este é um post em andamento, que inicialmente pensei em criar como página, mas pensei melhor e entendi que esta é uma classe de assuntos.
Portanto vou agrupar em links numa página especial sobre paradigmas

Referências:
Can Your Programming Language Do This? by Joel Spolsky
Functional Programming – Wikipedia
Mathematical Foundations of Functional Programming. Streicher, Thoms.
Digital Press – Lisp – 1990 – Common Lisp the Language, 2nd Edition – Steele, Guy L.
Símbolos matemáticos em html

Abrindo parêntesis

A minha descoberta do LISP

É sabido que este blog visa uma tarefa essencial: descomplicar a programação e voltar às raízes usando “C” e assembly.

Acabamos também transformando-o em uma colcha de retalhos que contém dicas sobre o melhor sistema da atualidade para se trabalhar com programação – o GNU/Linux – e suas ferramentas.

Acabo então, por puxar mais uma ponta nesta colcha, pois ontem acabei por penetrar em mais um baluarte remanescente da era de ouro dos computadores: o LISP.

Problemas originais

O primeiro problema que enfrentamos quando queremos programar é a nossa própria ansiedade em ver tudo “rodando”. Esta talvez seja a raiz de todos os problemas que enfrentamos após lançarmos aquela ideia num editor de textos e vê-la compilar “sem erros”. Na realidade esta é a verdadeira gênese de um inferno astral que surge ao “liberarmos o programa para o mundo”. Isto ocorre pois o mesmo, foi feito enfatizando os alogorítimos, em vez dos dados.

O dado, ou seja a informação sem tratamento, deveria ser tratado como cidadão de primeira classe, ao invés dos algorítimos o serem. E o planejamento cuidadoso de sua forma e estrutura é que faz a diferença entre um programa que “roda” e um programa que “resolve” um problema sem criar outros.

Na matemática, damos muita ênfase aos números e o processo envolve dar significado a eles, primeiramente, para depois agrupá-los e classificá-los. Na programação, deveriamos fazer o mesmo com os dados, antes de processá-los. Mas, caso o façamos, nos deparamos com uma realidade sutil, percebida por poucos: computadores não foram feitos para trabalhar com “textos”, mas sim com números. O próprio nome, computador, já existia antes de formalizar-se sua existência, e significa: contar, calcular…

Como fazer isto, então, com textos?

Há muito tempo percebi que a ferramenta mais amigável de um programador é o seu editor de textos e a mais pervertida é a sua IDE. A primeira é onde nasce o programa e ele pode ser analisado sem interferências ou falhas do ambiente. É o programa brotado da ideia para a tela, estático. A segunda é onde se criam os idiotas “chaplinianos” que pensam estar programando, quando na realidade estão apertando parafusos, ou melhor dizendo juntando, desonradamente, peças do trabalho de outros e atribuindo-as aos seus. Vide dotneticos, delphicos, javeiros e outros bichos mais…

Contatos imediatos do terceiro grau – Emacs

Na minha busca pela ferramenta certa, encontrei no ano passado e pela segunda vez na vida, o GNU/Emacs, e pude comprovar o poder de fogo desta arma. Depois de muito “atirar” com ela – e também de me ferir – percebi que ela se utiliza de uma engrenagem que a faz ter tanto poder e versatilidade: o LISP.

Adiei, até poder me dizer usuário de emacs, ou “emacser”, o aprendizado do funcionamento da engrenagem. Primeiro, porque sempre vi o LISP, como a maioria vê: um alien. Segundo porque, assim como todos, tenho outras coisas a fazer, em vez de estudar matemática. Melhor então me aproveitar do trabalho dos outros… (;-))

E nesta de “aproveitar o trabalho dos outros” sempre achei estranho lidar com os mesmos problemas que, ao serem dissecados até o fim, acabavam sempre degenerados em números, listas e quando se tratava de strings, a melhor solução parecia ser a recorrência, mas que por puro medo e preconceito eu abominava.

Forçando a barra e usando martelo como chave de fenda

Esta semana eu estava resolvendo um problema que me atormenta há muito tempo: como eliminar espaços extras numa string deixando apenas um no lugar e eliminando as bordas.

Abri a cabeça e fiz um código – feio – mas que funcionou bem. Só que recorrente. Testei de todo o jeito e notei que é muito estável. Aquilo me chamou a atenção: por que não usar isto mais vezes?

#include <ctype.h>
#include <stdio.h>

/* Objetivo: eliminar espaços duplicados, deixando apenas um
   no seu lugar e eliminar os espaços extra das extremidades 
*/

void shrinkstr( char *s, int count)
{
  while ( *(s + count) != 0 ) 
      *s ++ = *(s + count) ;
   *s = 0;
}

void jumpspcs( char * str, int * count )
{
  if (*str == 0) {
    str -= *count;
    if ( isspace(*--str) ) *str = 0;
    return;
  }

  if ( isspace(*str) ) {
    * count += 1;
    jumpspcs( ++ str, count );
  }

  else {
    str -= *count - 1 ;
    shrinkstr(str - 1, *count);

    if ( isspace(*str) ) {
      *str = ' ';
      str ++; // deixa apenas um espaço
    }

    *count = 0;
    jumpspcs( str , count );
  }
}

int main( int argc, char ** argv)
{
  char *str = argv[1];
  int n = 0;

  if (argc < 2)
  {
     puts("Uso: test \"   bla   bla   bla  \"");
     return 1;
  }
  jumpspcs( argv[1], &n);
  printf("'%s'\n", str);
  return 0;
}

Olhando para o código, percebi que o mesmo “não fica bem” numa linguagem como o C. Parece “torto”.

O motivo é muito simples: C, C++, Java, C#, etc… Possuem o mesmo DNA: Fortran. Além do claro fato que eu não sou matemático e muito menos programador de primeira linha.

Mas até eu percebo que usar estas ferramentas é como usar um martelo no lugar de uma chave de fenda para instalar um parafuso.

Olá matemática: o Cálculo revisitado

Esta semana também encontrei um velho conhecido: o Cálculo. Estava folheando o livro do James Stewart e fiquei maravilhado como um livro, bem diferente daqueles do Thomas Finney (nos quais já estudei), consegue ensinar, de forma tão fácil o que eu nunca tive coragem de digerir. O livro aborda conceitos práticos, reais e aplicáveis com o Cálculo e deixa-nos a real sensação que não somos tão burros, como os professores insistem em nos provar, ao invés de nos ensinar.

Por sorte, também encontrei outro livro, sobre LISP, este bem mais recente, do Conrad Barski, M.D.. Foi uma surpresa gratificante notar que sou muito idiota por ter tido “medo” e evitado esta linguagem.

O modo como o autor expõe os conceitos – tipo gibi e ainda por cima cria um “joguinho” nos exemplos – nos leva a achar muito do que já vimos e tentamos resolver com listas, árvores, strings, etc usando os recursos toscos das outras linguagens.

Como vi num exemplar antigo ( Agosto 79, Vol. 4, Num. 8 ) da revista Byte – uma relíquia que consegui via p2p – numa edição totalmente dedicada ao
LISP: o LISP é um assembly de alto nível feito para uma “maquina virtual”, John Allen.

“LISP é simples e difícil, elegante e ad hoc; é a beleza da mistura do previsível com o fortuito. LISP é uma linguagem de programação, sempre caracterizada como de “propósito especial” para processamento de listas. Mas LISP é tão de “propósito especial” quanto a matemática é para se processar cálculos de ponto-flutuante. Da mesma forma que existe mais matemática do que “contabilidade e escrituração” nas ditas linguagens de “propósito geral”.

A melhor descrição de programação em LISP é ela ser uma “linguagem de máquina” de alto nível cujos dados são organizados de forma diferente daquela de padrões de bits da maioria dos computadores, e o LISP é o assembly para esta máquina.”

Note que isto foi escrito em 1979, quando o JAVA nem sonhava em dar o ar da graça. Ou seja o LISP contém muito do que buscamos de forma primitiva, obter com os nossos “C’s” e “Pascais” que por aí vivem.

Daqui para frente

Eu ando bem cansado de ficar remoendo os problemas usando técnicas e artifícios – macetes mesmo – com a linguagem “C”. Sim gosto muito dela, mas falta um ingrediente: entendimento das raízes.

Instalei o CLISP no meu computador e fiquei muito animado e satisfeito com os resultados imediatos obtidos usando conceitos bem primitivos.

A parte difícil então, fica daqui por diante: como abandonar os velhos hábitos, tirar a máscara e aprender Matemática; de novo ?!…

Acho que o jeito vai ser “abrir um parêntesis” e recursivamente utilizar o LISP acoplado aos meus adorados programas em “C”, afinal a exemplo do RMS, o GNU/Emacs é exatamente isto: 30% C, 70% LISP.