Arquivo da categoria ‘coding’
Clojure e seus “Incantos”
Ta bom, eu sei que é encantos, mas resolvi escrever “Incantos” por postar aqui muito rapidamente sobre uma lib clojure chamada Incanter.
Durante a construção do JTornado, resolvi fazer um exemplo de utilização em clojure. A sensação que eu tive foi a mesma que você vai ter quando olhar o código abaixo. Algo do tipo: “c@#, esse negócio é impossível!”. Me senti exatamente como Brenton Ashworth se sentiu ao descrever seus primeiros contatos com a linguagem em uma entrevista a Fogus.
Mas não aceitei o desaforo de me sentir assim e encarei o aprendizado da linguagem com mais seriedade. Para a minha supresa, a linguagem é tão concisa e tras consigo uma ideologia tão profunda, que tudo é naturalmente compreendido. Imediatamente fiz uma conexão Os ensinamentos do Budha, principalmente no tocante a impermanência de todas as coisas.
Ok, não vamos gastar as poucas linhas que pretendo escrever.
Mas a ideia trazida por Rich Hickey é – guardadas as proporções – muitíssimo semelhante.
Por algum motivo achei um post do Michael Kohl (que inclusive me deu boas dicas de como melhorar a primeira versão deste exemplo), onde ele usa o Incanter para analisar – inclusive graficamente - a utilização de linguagens de programação em projetos hospedados no GitHub. Aquilo me saltou aos olhos de imediato.
Vamos chamar o Incanter de uma poderosa construção em clojure que integra elegantemente diversas libs java (veja a descrição no site) matemáticas, estatísticas e de plotagem. O resultado não poderia ter sido melhor. E nada como um bom motivo (ainda que você force a barra um pouco :p) pra usar algo que você quer aprender.
Na pós-graduação, a professora de Gestão de Pessoas passou um questionário para que pudéssemos visualizar nosso Estilo Motivacional. O teste se chama LEMO e visa detectar se você é uma pessoa de estilo Ação, Participação, Conciliação ou Manutenção. Sem entrar em detalhes, o teste consiste em anotar as respostas do questionário e efetuar somas simples por quesito, o resultado é categorizado em estilos dentro de uma situação normal de trabalho e numa situação de pressão.
Ok, não precisava desenvolver nada pra calcular, a professora até entregou uma planilha com tudo arrumado, era só preencher. Mas se eu preenchesse não seria eu. E aí vem:
(ns lemo (:use (incanter core io charts stats))) (def lemo (read-dataset "lemo.txt" :header true :delim \;)) (defn bar [data title] (bar-chart ["p" "a" "m" "c"] data :title title : x-label "Motivational Style" :y-label "Degree")) (defn line [n p] (doto (line-chart ["Normal" "Pressure"] [(sd n) (sd p)] :title "Standard Deviation" :y-label "Deviation" : x-label "Condition") (add-subtitle "From Normal to Pressure Conditions"))) (let [[norm press] (->> lemo to-matrix (partition-all 9) (map trans) (map #(map sum %)))] (view (bar norm "Normal Conditions")) (view (bar press "Under Pressure")) (view (line norm press))) ;;lemo test can be loaded from http://gist.github.com/526089
Susto? Provavelmente sim. Onde está o método main? Qual é o nome da classe? Bom, esquece tudo isso! Clojure nem é orientada a objeto, embora tudo nela seja um. #WIN.
O código acima basicamente lê um txt onde coloquei todas as minhas respostas (linha 4 a 6). No script observe um um binding (usando let) para duas variáveis de nomes norm e press cujos valores são o primeiro e segundo ítem da lista retornada de uma série de aplicação de funções:
- to-matrix: deve ser intuitivo, estou convertendo meu data-set em uma matriz
- (partition-all 9) : como optei por colocar todas as respostas juntas (em condições normais e de pressão), apenas organizei os dados por estilo, que corresponde as questões a,b,c e d. Então tenho 9 questões para uma e 9 para outra condição.
- (map trans): a função anterior particionou minha matrix em 2, uso a função nativa map, para gerar a matriz transposta de cada uma delas.
- (map #(map sum %)): A função anterior gerou uma transposta para cada matriz, ou seja, 2 matrizes, por isso o map outra vez, mas ao invez de aplica trans eu aplico uma função anônima #(map sum %). Esta função diz: para cada linha da matriz (map) aplique a função de soma (sum). Ah! Cada linha da matriz será passada como primeiro argumento (%) para a função anônima.
Sem atribuições, sem mutações, nada.
Isso é permitido devido à função ->>, que executa uma espécie de folding das funções listadas, aplicando na próxima função – como último parâmetro – o resultado da execução anterior. A gente já faz muito isso em programação funcional, e chama-se fold (dobrar). Mas, mais frequentimente “dobramos” listas de números, Strings, etc. Por que não dobrar uma sequencia de funções?
Pronto! Agora é só pegar os dados e brincar de gráficos.
Para mostrar os resultados, criei duas funções, a bar e a line (definidas por defn). A função bar recebe a primeira lista de valores (norm) – que corresponde a meu Estilo Motivacional em Situação Normal – e retorna um gráfico em barras:

Naturalmente, a segunda lista de valores de (press), mostra meu Estilo Motivacional em situações de Pressão. Mais uma vez usei bar para gerar o gráfico:

Por fim, e tão sem necessidade quanto calcular e gerar gráficos (a não ser a própria diversão e aprendizado), observei que em situação de pressão meus estilos tendem a se equilibrar. Quanto? Para saber o quão distante estão meus estilos nas duas condições, gerei um terceiro gráfico onde uso Desvio Padrão, a função sd do Incanter.stats. Note que em situação normal, meu estilo Conciliador é mais baixo, o que gera um desvio de aproximadamente 4.5 pontos. Com o equilibrio, passo a ter um desvio de pouco mais de 1.5 pontos. O gráfico a seguir mostra que mudando de condição, há um decrescimento no desvio.

Como foi possível notar, meu Estilo Motivacional predominante é o Manutenção. Isso significa (também) que sou capaz de fazer algo como este post só por diversão e a troco de algumas horas pensando e estudando.
Sugestão para executar o script em sua máquina: Cljr vai ajudar a instalar e rodar tudo redondinho inclusive com o claspath configurado. Lembre de executar um:
> cljr install incanter
É preciso executar o lemo.cljr no mesmo diretório que o lemo.txt. A versão utilizada no post é a {:major 1, :minor 2, :incremental 0, :qualifier “beta1″}.
Espero que tenha sido divertido, você encontra o original dos fontes em um dos meus Gists: Este. E lá você pode ver a evolução da coisa. Comecei brincando de calcular e terminei neste post (que decidi fazer hoje mesmo).
Antes que esqueça, o Incanter se inspirou no R, que é uma linguagem funcional para construção de computações estatísticas provinda do S. R possui forte semelhança com APL, que tem uma implementação feita pelo próprio criador da, chamada J. Ambas Sensacionais!
Até a próxima e não esqueça de me seguir no twitter: @paulosuzart.
Nota: no código, note que :y-label tem os dois pontos juntos à letra y, o que é não possível com a letra x, por isso ao espaço entre o : e o x. O wordpress resolveu colocar um emoticon ao detectar esta sequencia.
Python, Java NIO => JTornado
Desde o últmimo post parei com Scala. 0.o
Devido a um problema com as versões da linguagem (incompatibilidade binária e mudanças na estratégia de Collections para aumentar a compatibilidade com o Java), muito se especulou sobre a estabilidade da linguagem e muitas discussões acirradas (vejam os tweets entre @jboner e @codemonkeyism. Por este motivo tirei férias de Scala e mergulhei profundamente em Python.
Fui surpreendido com uma linguagem extremamente madura, poderosa e completa. Foi tão apaixonante quanto Scala. Como já desejava construir algo no GAE usando python, não perdi tempo e criei o Twittograph (@twittograph), o que deve ser em breve a nova maneira de pedir autógrafos aos seus ídolos.
Então estudei muito (não só Python): Eventlet, Twisted, Tornado, Linux Epoll, Python Select, Python Fabric, fiz Gists, Avro, Boost e Java NIO, clojure. Devo com certeza ter esquecido algo. Não dá pra comentar de cada um destes ou o post ficaria bastante extenso. Fica a dica: Python, Tornado e Clojure. Usem.
Passei a usar o Python Fabric no dia-a-dia, e usei o Tornado para construir o Twittograph. Como vocês podem perceber eu estava navegando pra todos os lados ao mesmo tempo, e as chances de ficar parado eram grandes, até que @abraaoisvi me alertou que eu deveria focar. Foi então que @rafaelfelini – até então recém apaixonado por python – sugeriu “construir” uma versão do Tornado em Java.
Assim nasce o JTornado. Construído em conjunto com o Rafael. Tá, o nome não é lá essa criatividade. Pensamos em Cyclone, Transtornado, Huracan, etc. Bom, deixa JTornado mesmo.

Se você quer praticidade, precisa conhecer o Tornado, feito pelo Facebook (link acima). Mas se você quer esta mesma praticidade em Java e sabe que Java para Web != Servlet. Conheça o JTornado. O JTornado pode ser visto como um framework web com um servidor de alta performance embutido, ou um servidor de alta performance com um framework web embutido. Este é um direcionamento que ainda vamos discutir.
O próprio @felipejcruz, criador do easy_tornado já se mostrou a favor do foco num framework para aplicações assíncronas de rede, que eventualmente oferece um framework web. Vamos ver!
Logo logo devo postar os percalços enfrentados para usar Java NIO e ao mesmo tempo usar low-level concurrency, leia-se threads. Como foi construir um server baseado em processos (Tornado) utilizando a JVM que nos limita neste aspecto. E muito mais. Devo escrever sobre algumas boas práticas – que acreditamos que sejam boas – para o uso de NIO aliado à alta performance com threads.
Veja algumas discussões no Stackoverflow.com durante este tempo:
- Selector.select(timeout) x Selector.selectNow()
- NIO Best Practices – SelectableChannel and InterestOps
Como não pode faltar código num post, segue uma micro app usando o JTornado, mas escrita em Clojure:
;Starts an JTornado HTTP Server and a sample RequestHandler.
; Bit verbose due to compilation directives. Recommendation is to generate
; a set of macros to hide this.
(ns org.ctornadoweb
; Compiled and implements a static main method to start the server
(:import (org.jtornadoweb HttpServer)
(org.jtornadoweb.Web$Application)
(org.jtornadoweb.Web$RequestHandler))
(:gen-class :prefix "server-"))
(gen-class
:name org.ctornadoweb.MyHandler
:extends org.jtornadoweb.Web$RequestHandler
:prefix "do-")
(defn do-get [this]
"Handles the HTTP GET method"
(.write "hello clojure"))
(defn do-post [this]
"Handles the HTTP POST method"
(.write (.getArgument "name" "default" false)))
(defn server-main []
"main method"
(.listen
(org.jtornadoweb.HttpServer.
(.add (org.jtornadoweb.Web$Application.) "/" org.ctornadoweb.MyHandler)
false nil false) 8089))
;use (compile 'org.ctornadoweb)
Basta fazer um curl http://localhost:8089 e tudo funcionará
Aguarde o próximopost para informações completas de Java NIO e JTornado.
Update: Desde que a versão Scala 2.8.0 final foi liberada, retomei os estudos e meu interesse pela linguagem continua. A propósito, o único motivo para o JTornado ser construído em Java é ganhar tempo, pois os colaboradores se sentem mais a vontade com Java. Provavelmente algumas funcionalidades podem ser escritas em Scala ou até mesmo Clojure.