Codemountain, Paulo Suzart's Blog

Arquivo da categoria ‘coding

Clojure e seus “Incantos”

with 3 comments

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.

Written by paulosuzart

agosto 19, 2010 at 10:17 pm

Publicado em clojure

Etiquetado com ,

Python, Java NIO => JTornado

leave a comment »

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:

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.

Written by paulosuzart

julho 23, 2010 at 2:51 pm

Publicado em Java, nio, python

Etiquetado com , ,

Seguir

Obtenha todo post novo entregue na sua caixa de entrada.