Introdução à Linguagem Clojure

Propaganda
clojure_
Linguagem
Introdução à
Clojure
Um guia rápido e prático sobre a linguagem,
suas ferramentas e frameworks
Leandro Ribeiro Moreira | [email protected]
Diverte-se com desenvolvimento de sistemas, atualmente na ThoughtWorks Brasil. Quando sobra
tempo, escreve em seu blog (leandromoreira.com.br) sobre T.I.
A ideia básica do artigo é explorar a linguagem de modo
a demonstrar seus conceitos chave, construções básicas, tipos, alguns exemplos e ferramentas bem aceitas
na comunidade. Tudo isso de um jeito prático e rápido.
A finalidade não é servir como um guia completo para
linguagem, mas sim como uma apresentação curta da
mesma. Logo, se o leitor se interessar e quiser se aprofundar, há referências de livros e links que podem ajudar esse aperfeiçoamento de conhecimento. Note que,
por questões de simplicidade, adotei o termo função
genericamente, sendo que às vezes pode se referir na
verdade a uma macro, uma forma especial ou outra estrutura da linguagem.
Clojure é uma linguagem dinâmica, de propósito
geral, escrita em Java, de código-fonte aberto e que
roda sobre a Java Virtual Machine (JVM). Atualmente, há versões da linguagem para .NET (CLR) e JavaScript. Seu criador, Rich Hickey, a concebeu como
um dialeto Lisp (uma das mais antigas linguagens de
programação), mas com muitas melhorias e facilidades na sintaxe (syntactic sugar). Clojure também
se inspirou nas boas ideias das linguagens Python e
Haskell. Apesar de conseguir criar eou reusar programas no paradigma orientado a objetos, Clojure tem
como paradigma a programação funcional (veja o
quadro sobre o assunto). Diferentemente de outras
linguagens funcionais como Haskell,
Clojure é impura e permite a mutabilidade (side-effects).
A escolha do nome da linguagem
foi fortemente influenciada pelo termo da computação científica conhecido como closure juntamente com a
plataforma Java. uma closure pode ser exemplificada como a capacidade que uma função f1, retornada
dentro do corpo de outra f2, tem de referenciar variáveis locais da função f2 mesmo estando fora do
contexto de definição das variáveis. Veja o exemplo
implementado em JavaScript.
19 \
var f2 = function(){
var contadorExterno = 0;
var f1 = function(){
contadorExterno = contadorExterno + 1 ;
return contadorExterno;
};
return f1;
};
var f1 = f2(); //retorna a função f1
alert(f1()); //mostra 1
alert(f1()); //mostra 2
Além da vantagem de ter um enorme alcance
oferecido pela JVM, Clojure também se integra facilmente com código Java. No entanto, ultimamente
a linguagem está tendo mais foco devido às facilidades que Clojure proporciona para se escrever sistemas distribuídos sem se preocupar com locks e ou
sincronização. Um dos ideais de Clojure para resolver o problema da concorrência é ter como premissa
básica o fato de que quase tudo é imutável, e o que
não é deve ser tratado dentro de um contexto transacional, usando um modelo STM (softtware transactional memory). É importante observar que Clojure
não resolverá os problemas de concorrência que um
código legado Java já possui.
Clojure é uma linguagem homoiconic, um nome
bem diferente para demonstrar que os programas
escritos na linguagem são representados por estruturas de dados. A linguagem é definida em termos
da análise das estruturas de dados e não da sintaxe
da mesma. Essa diferença dá o poder de construção
sobre a linguagem, ou seja, caso haja algo que não
existe ainda na linguagem, você pode simplesmente
criar essa “sintaxe” nova.
Mesmo tirando todas as vantagens citadas anteriormente, penso que a linguagem é interessante
e vale a pena ser estudada por ser limpa, objetiva,
propor reusabilidade ao máximo e também porque
faz o desenvolvedor pensar de um modo totalmente diferente da forma imperativa de criar programas
computacionais.
Outro fator importante a ser citado é a quantidade e qualidade de suporte da comunidade. Ao contrário de outros dialetos Lisp, Clojure está sendo bem
mais difundida, entendida e explorada. Basta ver o
“ecossistema” em volta da linguagem, que tem desde
ferramentas para automação de projetos e resolução
de dependências a muitos frameworks de propósitos
gerais.
Instalação
Para instalar e utilizar Clojure, você deve ter
/ 20
instalado e disponível no seu sistema operacional o
Java 5 ou outra versão mais atual. A instalação consiste apenas em baixar o .zip do endereço http://clojure.org/downloads o qual contém a última versão
estável. No momento da escrita do artigo, essa versão é a 1.3.0. Depois de baixado, extraia o arquivo zip
e observe que há um jar com nome clojure-1.3.0.jar.
Para seguir os exemplos do artigo, você deve entrar pelo seu prompt/terminal na pasta onde baixou
o descompactou o jar e executar o comando java -cp
clojure-1.3.0.jar clojure.main ou java -jar clojure-1.3.0.jar. Esse comando faz com que o seu terminal
se transforme em um ambiente interativo onde você
insere código e o mesmo é avaliado e executado. Tal
ambiente é muito bom para testar códigos rapidamente. Para quem conhece Ruby é bem similar ao
IRB. A esse ambiente é dado o nome REPL (read–
eval–print loop) e nesse local você poderá executar
os exemplos do artigo.
Outros REPLs
Caso não queira instalar na sua máquina ou apenas por curiosidade quiser testar os códigos, pode
utilizar também outros REPL. Um deles é on-line e
pode ser acessado através do endereço http://tryclj.
com/. Você também pode usar seu smartphone ou
tablet, com android embutido, pra testar códigos
pelo REPL que pode ser obtido no endereço https://
market.android.com/details?id=com.sattvik.clojure_repl (figura 1, QRCODE).
Alô mundo
Antes de demonstrar o exemplo ‘alô mundo’ em
clojure, é necessário ressaltar novamente que todos
os exemplos podem ser executados diretamente no
REPL; logo, você pode deixar o mesmo aberto enquanto lê o artigo.
Programas escritos em Clojure são estruturas
de dados conhecidas como listas. Para o exemplo,
iremos criar uma lista com dois itens, a função e o
argumento.
Listagem 1. Exemplo alô mundo.
(println “Alô mundo”)
Para executar o programa, basta pressionar a tecla Enter, e verá a execução do famoso exemplo de
introdução a linguagens de computador. Como dito
anteriormente, programas em Clojure são listas, e
tais listas são criadas utilizando-se parênteses e com
itens dentro dos parênteses, opcionalmente separados por vírgula.
Simplificando um pouco todas as nuances possíveis, quando essa instrução for lida pelo REPL, ele
irá tentar executar o primeiro item da lista como
uma função, que por sua vez recebe o restante da lista como parâmetro. Apesar de parecer uma sintaxe
da linguagem, uma palavra reservada ou ainda uma
função especial, a função println não é. É uma função ordinária da linguagem como qualquer outra, e
ela está definida dentro de um namespace, conceito
similar ao pacote java.lang em Java, que é disponibilizado automaticamente para você utilizar.
O mesmo exemplo poderia ser escrito usando
uma variável interna para guardar a cadeia de caracteres “Alô mundo”. Para criar essa variável, basta usar
a função def, que espera como argumento um nome
e, opcionalmente, um valor. Veja na Listagem 1.1 o
mesmo exemplo, mas utilizando uma variável interna. Observe também que para se criar comentários no
código utiliza-se o caractere ponto-e-vírgula.
Listagem 1.1. Exemplo alô mundo com variável.
; Alô mundo por variável
(def alo-mundo “Alô mundo”)
(println alo-mundo)
Principais tipos
Assim como outras linguagens dinâmicas, Clojure é tipada. Conhecer seus tipos básicos é essencial
para a criação de programas. Alguns tipos em Clojure
são exatamente os mesmos da linguagem Java, como,
por exemplo, o tipo String.
O tipo responsável por dar nomes a coisas em
Clojure é o símbolo. No exemplo alô mundo, note que
o nome da função println é um símbolo, mas o mesmo não se restringe apenas à nomeação de funções
e também é utilizado na definição de namespaces e
outros. Exemplos de símbolos: nome-da-funcao, +,
br.namespace/funcao etc.
Os números são bem simples de serem entendidos. Assim como em Java e outras linguagens, os literais numéricos irão representar os números. Há um
tipo numérico novo, a fração (ratio), não muito conhecido para alguns desenvolvedores. Esse tipo mantém os valores de uma divisão na forma dividendo por
divisor sem perder a precisão. Ao usar esse novo tipo,
você pode fazer operações aritméticas normalmente
sem se preocupar. É como se estivesse trabalhando
com tipos numéricos simples. Exemplos de números:
1, 30M, 3.14, 1 ⁄ 3 etc.
É importante dizer que não há promoção automática dos tipos numéricos. O código da Listagem 2
executa sucessivas multiplicações por mil que resulta
não em um gigantesco número, mas sim em uma exceção de overflow. Uma maneira de corrigir o código
seria colocar um M no final do literal numérico, que
o força a ser um BigDecimal. Versões mais antigas da
linguagem faziam essa promoção automática.
Listagem 2. Exceção de overflow.
(* 1000 1000 1000 1000 1000 1000 1000 1000)
Para representar os boleanos basta utilizar os
literais true e false. Para Clojure, exceto nil e false,
tudo é true, inclusive o 0. O literal nil é equivalente
ao null da linguagem Java.
O tipo literal é exatamente o tipo String do Java,
com sua imutabilidade e métodos. A diferença fica no
tipo caractere, que é representado por barra e o caracter \x, onde x é o próprio caractere. Observe que \n
não tem o mesmo valor que tem Java, sendo apenas o
caractere n. Exemplos de caracteres: \a, \n, \newline,
\tab etc.
Um tipo similar a cadeia de caracteres, porém
com outro propósito são as palavras-chave (keywords). Para criá-las, basta adicionar ao início do literal
dois pontos. São principalmente usadas como chaves de um mapa. Exemplos de palavra-chave: :chave,
:campo-nome etc.
Coleções
Coleções são tipos abstratos que representam
diversos tipos repositórios de itens. Em Clojure, as
coleções têm algumas propriedades compartilhadas.
Todas são heterogêneas, ou seja, você pode ter diversos tipos dentro de uma mesma coleção. A linguagem
trata todas as coleções como sequences, uma abstração de Clojure na qual você consegue aplicar funções
comuns sobre essas estruturas de dados.
Clojure utiliza um conceito conhecido como estrutura de dados persistentes para implementar todas suas coleções. Nesse modelo, não há mudanças
quando você adiciona, remove ou atualiza um item
da coleção, o que ocorre são apenas ligações entre essas mudanças, que preserva versões anteriores de sua
coleção, e isso torna as coleções efetivamente imutáveis. Na prática, quando você adiciona um item a uma
coleção, na verdade você está recebendo uma nova
coleção. Tal fato pode assustar alguns desenvolvedores por medo de baixa performance ou alto consumo
de memória, mas a linguagem foi projetada para não
fazer apenas cópias e ser inteligente o bastante para
ligar tais coleções.
Um das estruturas de dados mais simples, o vetor,
pode ser criada usando colchetes ou a função vector,
como, por exemplo.
[ “item1”, :item2, [ ] ]
(vector “1” 2 :tres)
A estrutura de dados que têm seus valores ordenados e tais podem ocorrer mais de uma vez, conhecida como lista, também é suportada por Clojure. Tais
listas podem ser criadas usando apóstrofo seguido de
parênteses ou com a função list, como, por exemplo.
21 \
(def pilha ‘(“jpa” “jsf”))
(def hobbies (list “música”“boxe” “baralho”)
Por diversas razões, às vezes precisamos de listas
que não pode permitir repetições de itens. Esse tipo
de estrutura é conhecido como conjunto. Para criar
conjuntos em Clojure, podemos utilizar a notação
sustenido seguido de chaves ou a função hash-set,
como pode ser visto nos exemplos.
#{“f1” “rally” “fórmula truck” “f1” “indy”}
; a repetição do item “f1” será ignorada.
(def centro-oeste (hash-set :go :df :ms :mt)
Quando se deseja criar uma função para um propósito menor, seja para fazer uma simples seleção
ou algo mais trivial, pode-se criar funções anônimas.
Tais funções não são nomeadas e nem precisam ser
definidas por meio da função defn. Na Listagem 4 é
apresentada uma função chamada operação, que recebe uma função mais dois argumentos e imprime o
resultado da aplicação dos parâmetros sobre a função
passada.
A ideia é criar quatro funções anônimas, que representem soma, subtração, multiplicação e divisão,
e passá-las para a função operação. Para criar funções
anônimas, pode-se utilizar a função fn, a qual é similar a defn, omitindo apenas o seu nome. As funções
anônimas possibilitam várias técnicas úteis, e uma
delas é expor o contexto interno de uma função a
funções externas, ou carregá-los além de sua definição, o que pode ser visto como um closure.
Por último, temos a coleção do tipo mapa, a qual é um
tipo abstrato onde se faz associações de chaves a valores, por várias vezes visto como sinônimo de dicionário ou vetor associativo. Para criá-las em Clojure,
você pode usar chaves ou uma função como a hash- Listagem 4. Funções anônimas.
-map, e mesmo a vírgula sendo opcional nos mapas,
seu uso é encorajado devido a melhor legibilidade do
(defn operacao [funcao x y]
código.
(println (funcao x y)))
(def nosql-bd
{:server “192.168.101.15”, :port 8584, :cloud false})
(def cidade
(hash-map :nome “são paulo”, :sigla “sp”,
:per-capita 32493))
Função a unidade central
Depois de conhecer um pouco sobre os tipos da
linguagem, o próximo passo natural é estudar sua estrutura central. Nas linguagens orientadas a objetos,
essa estrutura central seria a classe: já em Clojure, é
a função. Seus programas poderão ser expressos por
meio de funções, e sua composição guiará ao propósito de sua ideia para um sistema.
Para se criar uma função, basta utilizar outra
função de uso bem simples, chamada defn. É mostrado na Listagem 3 a criação de duas funções, onde
a primeira simplesmente imprime “alô mundo” no
console/prompt enquanto a segunda recebe dois números e devolve a soma dos mesmos, usando a função
+ que realiza a soma dos parâmetros passados. Note
que a função defn recebe um símbolo, que define o
nome da função, seus parâmetros, ou ausência deles,
através dos colchetes e o corpo da função envolto em
parênteses. Abaixo da definição das duas funções, seguem exemplos de como executar ambas.
Listagem 3. Criar funções.
(defn alo-mundo [] (println “alô mundo”))
(defn soma [x y] (+ x y))
(alo-mundo)
(println (soma 2 3))
/ 22
(operacao (fn [a b] (+ a b)) 2 2)
(operacao (fn [a b] (- a b)) 4 6)
(operacao (fn [a b] (* a b)) 1 0)
(operacao (fn [a b] (/ a b)) 2 4)
Controle de fluxo por funções e não
sintaxe
Em uma linguagem funcional, normalmente, todas suas estruturas de controle de fluxo, sejam elas
condicionais e ou de iterações, são construídas sobre
funções, e Clojure também segue essa mesma regra.
Essa pequena diferença é, talvez, a que causa maior
estranheza aos novos adeptos de uma linguagem
funcional. Por exemplo, suponhamos que você queira
imprimir todos os valores de um dado vetor. Compare
na Listagem 5 como esse código poderia ser escrito
em Java e Clojure.
Listagem 5. Iteração : Java & Clojure.
//Java
final String[] valores = new String[] { “um”, “dois”, “três”};
for (String valor : valores) {
System.out.println(valor);
}
;Clojure
(map println [1 “dois” :tres])
A intenção da comparação do código da Listagem 5
não é pelo tamanho ou complexidade, mas apenas
para demonstrar que, enquanto nas linguagens imperativas o que é esperado é uma sintaxe nova, em
Clojure você utiliza uma função ou outra pra iterar.
Outra forma de se controlar o fluxo de programas
é por meio de instruções condicionais: os famosos
if’s. Em Clojure tem-se a função if para esse fim. O
seu uso é muito simples: ela espera dois parâmetros
obrigatórios, a condição e uma instrução, caso a condição seja verdadeira, e um opcional, que seria executado caso a condição fosse falsa. Na Listagem 6 é
mostrado um exemplo bem simples de uma função
que recebe um número, checa se o mesmo é maior do
que dez e retorna um texto dizendo se é maior ou não
do que dez.
Listagem 6. Função determina maior do que dez.
(defn maior-do-que-dez [numero]
(if (> numero 10)
(str “Sim”)
(str “Não”)))
;Exemplo de uso
(println (maior-do-que-dez 100))
Interoperabilidade com Java
Clojure fornece muitas funções e facilidades para
essa interoperabilidade, o que faz a tarefa de usar Java
dentro da linguagem muito simples. Pode-se invocar
um método utilizando as notações apresentadas na
Listagem 7. Vale lembrar que Clojure já importa automaticamente o namespace java.lang.
Listagem 7. Invocando um método Java em Clojure.
; Métodos de instância
(.toUpperCase “gaucho”)
(. “pessoense” toUpperCase)
; Métodos de classe
(Math/PI)
(.Math PI)
Para criar instâncias de objetos há pelo menos duas
formas: a primeira utilizando a função new, e outra
na qual você coloca o nome da classe seguido de um
ponto. Lembrando que Java optou por organizar as
classes em pacotes, e assim, para utilizar uma classe
nos referimos ao caminho completo ou importamos
o pacote ou classe. Em Clojure existe a função import, que faz justamente a importação dos pacotes e
ou classes.
O encadeamento de chamadas a métodos pode
ser feito utilizando a função dot, ou mais facilmente
a função dotdot. Alguns métodos requerem parâmetros para sua execução, e segue-se a mesma regra de
passagem de parâmetros a funções, bastando usar o
espaço e informar tais parâmetros. Há também uma
função bastante útil chamada bean. Tal função recebe uma instância de objeto e retorna um mapa do
padrão JavaBean, e de posse desse mapa, pode-se fazer consultas a esse mapa utilizando a chave como
acessor para o valor. Todos os conceitos explanados
anteriormente estão exemplificados e comentados na
Listagem 8.
Programação funcional
Definir o que significa programação funcional é uma tarefa árdua, apesar de ser um conceito
que pode apresentar várias concepções há algumas definições que são bem aceitas pela grande
maioria dos desenvolvedores. Pode-se dizer que
programação funcional é um paradigma de desenvolvimento que enfatiza a aplicação de funções, em contraste com o estilo de programação
imperativo, onde o que é realçado são as mudanças no estado dos programas. A programação funcional tem suas raízes no cálculo lambda. Segue
abaixo uma descrição de alguns conceitos sobre
esse paradigma.
Funções sem side-effect: a princípio uma
função não deveria causar um efeito fora de seu
escopo, ou seja, ela deveria ser uma unidade atômica que não causa mudança de estado no programa. Claro que, na prática é quase impossível
escrever um programa onde não há uma função
que cause mudanças externas.
Dados imutáveis: nesse paradigma deve se
evitar a mutabilidade, que é uma das dicas básicas para o bom desenvolvedor Java. Sabendo que
programas de computador vão causar e persistir
efeitos externos, as linguagens implementam jeitos para que os programas possam ser mutáveis
quando necessário.
Funções como cidadãos de primeira classe:
você consegue usar funções como se fossem objetos num sistema OO, você pode passar uma função para outra e ou receber, da execução de uma
função, outra função.
Construções básicas como funções: ao invés
de uma sintaxe específica para iterações e estruturas condicionais, construções básicas de uma
linguagem de programação, a solução é utilizar
funções, seja pra iterar sobre uma coleção ou controlar o fluxo dos programas.
23 \
/eu uso
Phil Calçado
Desenvolvedor na SoundCloud, a plataforma que lidera a distribuição e socialização de música e áudio na Internet. Ele
bloga em http://philcalcado.com e pode ser encontrado no twitter como @pcalcado.
Por volta de 2006, eu estava em um projeto Ruby e comecei a me deparar com as limitações desta linguagem em termos de metaprogramação. Ao procurar uma melhor maneira de enfrentar estes problemas
eu acabei aprendendo Common Lisp e Scheme. Eu fiquei imediatamente excitado com as possibilidades
que Lisp traz, mas estas duas linguagens estavam muito distantes da minha realidade, que era basicamente projetos em Ruby, Java e C++.
Quando Clojure foi anunciada eu vi a oportunidade que faltava. A linguagem não traz algumas das
principais vantagens de Lisp, como reader macros, mas ainda assim provê um conjunto de ferramentas
fundamentais para a criação de Domain-Specific Languages; além do suporte bem maduro à Programação Funcional.
Hoje em dia eu uso Clojure para sistemas de análise de dados e também aplicações web. A produtividade que se atinge ao dominar o desenvolvimento em Lisp com emacs e seu REPL não possui equivalente
em nenhum outro ambiente que eu conheça.
Listagem 8. Interoperabilidade.
muitas dessas suportam algumas técnicas para otimização de performance. A linguagem Clojure suporta a ideia de dar dicas (hints) sobre os tipos para
; Criar objetos
ajudar o compilador a compilar um código bem mais
(new java.util.Date)
rápido, mas ao mesmo tempo seu código fica menos
(java.util.Date.)
flexível. Para dar essas dicas ao compilador, você utiliza os metadados da linguagem, ou seja, dados sobre
; Importar pacotes/namespace
os dados.
(import java.util.Date)
Para criar metadados, basta utilizar o caractere
; Multiplas classes importadas;
acento circunflexo. Esse metadado pode ser aplicado
(import ‘(java.util Date Calendar)
para informar os tipos, sejam eles primitivos, não‘(java.text.DateFormat))
-primitivos e arrays. Em tipos primitivos, basta utilizar o acento circunflexo antes do nome: ^int, e para
; Encadear chamadas a métodos.
os tipos complexos a regra é a mesma (ex: ^String). Já
(. (. “dkcr” toUpperCase) toLowerCase)
os arrays seguem uma regra um pouco diferente: os
; ou simplifcando, tendo menos parênteses do que Java.
mesmos são declarados como plurais dos tipos primitivos; logo, o metadado ^floats está informando ao
(.. “dkcr” toUpperCase toLowerCase)
compilador que espere um array de float.
Para exemplificar e quantificar o uso das dicas
; Passagem de parâmetros aos métodos
de tipos, vamos construir um exemplo simples que
(System/getProperty “os.name”)
se baseia em uma função que conta o número de caracteres de uma String. Iremos escrever duas funções,
; JavaBean em forma de mapa
uma com e outra sem hint. Para testar, vamos utilizar
(def date-map (bean (java.util.Date.)))
cada uma das funções em uma lista de 5.000.000 de
; Obtendo os segundos e o tempo do mapa
itens, somar todas essas contagens e ao mesmo tem(:seconds date-map)
po marcar o tempo gasto. Depois de executar o código
(date-map :time)
da Listagem 9, observe que a versão sem hint levou
em média 4.000 milissegundos, enquanto a versão
com os hints levou em média apenas 365 milissegundos, uma diferença de mais de 100%. Lembre-se, fuja
Dicas de performance
Geralmente, as linguagens dinâmicas são mais de ajustes de performance prematuros, deixe existir
lentas do que as estaticamente tipadas. No entanto, a real necessidade para só então realizar os ajustes
necessários.
/ 24
Listagem 9. Funções e Benchmark.
; Funções
(defn contar [valor] (.length valor))
(defn contar-com-hint [^String valor] (.length valor))
; Benchmark
(time (reduce + (map contar (repeat 1000000 “aeiou”))))
(time (reduce + (map contar-com-hint (repeat 1000000
“aeiou”))))
Ferramentas, Frameworks e afins
Um dos fatores que pode mostrar o quanto uma
linguagem está sendo usada, testada e difundida são
as ferramentas e frameworks existentes para a mesma. A linguagem, apesar de bem nova e em evolução,
já tem suporte em diversos IDEs bem como uma ampla gama de frameworks escritos em Clojure.
Sempre que se fala em uma nova linguagem, a
comunidade procura por IDEs para suportar a mesma, e para aqueles que desejam utilizar Clojure já há
suporte em alguns ambientes. Para os que gostam do
Netbeans, há um projeto paralelo chamado EnClojure (http://enclojure.org/). Para os amantes do Eclipse,
há um plugin chamando Counter ClockWise (http://
code.google.com/p/counterclockwise/). E para aqueles que não deixam de utilizar o IntelliJ, este também
já suporta a linguagem via plugin (http://plugins.
intellij.net/plugin/?id=4050). Por fim, mesmo não
sendo classificado como IDE por alguns, já há suporte
amplo para Clojure nos editores de texto Emacs e vi.
Para automação, resolução de dependências e
outros, a linguagem conta com uma ótima ferramenta chamada Leiningen, ou apens lein (https://github.
com/technomancy/leiningen). Com essa ferramenta você consegue criar um projeto esqueleto, rodar
testes, empacotar, implantar seus jars, inclusive para
um repositório on-line como o Clojars (http://clojars.
org/), dentre outras tarefas. É bem comum ver projetos no github que utilizam o padrão de pastas e organização proposto pela ferramenta.
Como não deveria faltar, há frameworks para testes também para Clojure. Um deles é o Midje, e a escolha do mesmo como exemplo principal se deu ao
fato de seu amadurecimento, quantidade de ajuda
disponível e constantes atualizações. De uma forma
bem simples, o criador do framework resolveu tratar,
dado a natureza da linguagem, os testes como fatos,
logo, para testar se um mais um é dois, você pode escrever um fato.
Vale citar que o provedor de plataforma nas nuvens (PaaS) Heroku já tem suporte à implantação de
projetos Clojure, o que faz seu alcance ainda mais
amplo, indo de um simples entusiasta que deseja testar a linguagem a um start-up que deseja apostar nessa nova linguagem. O padrão de integração escolhido
pelo Heroku foi os projetos gerenciados pelo lein.
Considerações finais
O intuito do artigo não é ser um guia completo,
mas sim os primeiros passos e uma visão geral para
que você se liberte um pouco do medo e comece a
estudar e se aprofundar. Assuntos como sequences,
namespace, macros, metadata, protocols, multimétodos, agents, refs, atoms e outros ficaram de fora por
questões de escopo e complexidade. Aqueles que desejam ser mais eficientes e usar a linguagem de fato,
devem dominar tais assuntos, bem como o estudo e
uso mais apropriado e aprofundado das ferramentas
e frameworks.
Clojure oferece, entre outras coisas, alta reusabilidade, o alcance da JVM, acesso a todas as bibliotecas
Java já existentes, despreocupação de locks e sincronização na criação de aplicativos multithread, uma
comunidade forte e ferramentas e frameworks bem
testados. Tudo isso faz de Clojure, no mínimo, uma
linguagem a ser investigada.
/referências
Links
> http://clojure.org/
> http://en.wikibooks.org/wiki/Learning_Clojure
> http://tryclj.com
> https://github.com/technomancy/leiningen
> http://clojars.org/
> https://github.com/marick/Midje
> http://philcalcado.com/tags/clojure/
> http://leandromoreira.com.br/category/clojure/
Livros
> The Joy of Clojure, FOGUS, Michael e HOUSER, Chris;
Ed. Manning
> Programming Clojure, HALLOWAY, Stuart; Ed.
Pragmatic Bookshelf
> Clojure in Action, RATHORE, Amit; Ed. Manning
(fact (+ 1 1) => 2)
25 \
Download