Clojure
Clojure é um dialeto da linguagem de programação Lisp criado por Rich Hickey[1]. Clojure é uma linguagem de programação de propósito geral com ênfase em programação funcional[2]. É executada na Máquina Virtual Java (JVM) por padrão, mas existem versões alternativas para outros ambientes de execução, como Clojure CLR[3], que compila código para a plataforma .NET e ClojureScript[4], que compila código Clojure para JavaScript. Como outros Lisps, Clojure trata código como dados e tem um sistema de macros integrado. O processo de desenvolvimento atual é conduzido pela comunidade e supervisionado por Rich Hickey como seu ditador benevolente perpétuo[5] (BDFL em inglês).
Clojure | |
---|---|
Paradigma | funcional |
Surgido em | 2007 |
Última versão | 1.10.0 |
Criado por | Rich Hickey |
Estilo de tipagem | forte, dinâmica |
Principais implementações | JVM, CLR, JavaScript |
Dialetos | Lisp, Scheme, Common Lisp |
Influenciada por | Lisp, Prolog, ML, Haskell, Erlang |
Influenciou | Elixir, Hy, Pixie, Rhine |
Licença | Eclipse Public License |
Extensão do arquivo | .clj, .cljs, .cljc, .edn |
Página oficial | clojure.org |
Clojure incentiva imutabilidade e estruturas de dados imutáveis. Enquanto o seu sistema de tipos é totalmente dinâmico esforços recentes também têm procurado a implementação gradual de tipagem forte. Clojure incentiva programadores a serem explícitos sobre o gerenciamento de estado e identidade. Este foco em programação com valores imutáveis e explícitos no decorrer do tempo se destina a facilitar o desenvolvimento de programas mais robustos, especialmente os vários segmentos.
Clojure é utilizada com sucesso na indústria por empresas como Walmart, Puppet Labs[6] e outras empresas de software de grande porte. O suporte comercial para Clojure é fornecido pela Cognitect, que faz parte do grupo Nubank[7]. A última versão estável da linguagem Clojure é a 1.10, lançada em 17 de dezembro de 2018. A primeira versão estável foi a versão 1.0, lançada em 4 de maio de 2009. Clojure é um software livre disponível pela Eclipse Public License[8].
História e processo de desenvolvimento
editarRich Hickey é o criador da linguagem de programação Clojure[1]. Antes de desenvolver a linguagem Clojure ele trabalhou na dotLisp, um projeto semelhante com base na plataforma .NET. Ele também desenvolveu a interface jfli (uma espécie de ponte para usar recursos do Java para Common Lisp), FOIL (uma interface de objetos externos para Lisp) e Lisplets (uma interface amigável do Lisp para Java Servlets). Esses projetos eram tentativas anteriores para criar algum tipo de interoperabilidade entre Lisp e Java. Hickey gastou cerca de 2 anos e meio trabalhando na linguagem Clojure antes de lançá-la publicamente, muito desse tempo trabalhando exclusivamente na linguagem, sem nenhum financiamento externo. No final deste período Hickey enviou um e-mail anunciando a linguagem a alguns amigos na comunidade Common Lisp. O processo de desenvolvimento é voltado para a comunidade e o desenvolvimento é gerenciado no site da comunidade Clojure. O site contém documentos de planeamento e um rastreador de problemas onde bugs podem ser reportados. Discussões gerais sobre o desenvolvimento acontecem no Google Groups (em inglês). Enquanto qualquer um pode enviar relatórios de erros e ideias, para contribuir com correções é preciso assinar o acordo de contribuição Clojure[9], os bilhetes JIRA são processados por uma equipe de triagem e, finalmente, Rich Hickey aprova as alterações[5].
Filosofia do design
editarRich Hickey desenvolveu a linguagem Clojure por desejar uma versão moderna da linguagem Lisp para programação funcional[10], simbiótica com a já estabelecida plataforma Java[11], e desenhada para computação concorrente.
A abordagem adotada na linguagem Clojure para a manipulação de estados é caracterizada pelo conceito de identidades, estas representadas por uma série de estados imutáveis com o decorrer do tempo. Como os estados são valores imutáveis, um número indefinido de processos pode operar sobre os mesmos em paralelo, e a concorrência se torna uma questão de gerenciar as mudanças de um estado para o outro. Para esse propósito a linguagem fornece muitos tipos mutáveis, com uma semântica bem definida que permite controlar a transição entre os estados de forma eficiente.
Características
editarVersão | Lançamento | Principais características adicionadas |
---|---|---|
2007-10-16 | primeira versão pública | |
1.0 | 2009-05-04 | Primeira versão estável |
1.1 | 2009-12-31 | Futures |
1.2 | 2010-08-19 | Protocolos |
1.3 | 2011-09-23 | Suporte melhorado a primitivos |
1.4 | 2012-04-15 | Leitores literais |
1.5 | 2013-03-01 | Redutores |
1.6 | 2014-03-25 | API Java , algoritmos de hash melhorados |
1.7 | 2015-06-30 | Transdutores e leitores condicionais |
1.8 | 2016-01-19 | Funções de string, links diretos, servidor de socket |
1.9 | 2017-12-08 | Integração com spec, CLI (ferramentas via linha de comando) |
1.10 | 2018-12-17 | Relatório de erro aprimorado, compatibilidade Java |
O código Clojure é executado na máquina virtual Java e como resultado se integra com o ambiente Java permitindo invocar código Java a partir do código Clojure, assim como código Clojure também pode ser invocado a partir de código Java. A comunidade utiliza a ferramenta Leiningen para automação de projetos, fornecendo suporte para a integração com o Maven. Leiningen lida com o gerenciamento de pacotes do projeto e dependências e é configurado usando código Clojure.
Como a maioria dos outros Lisps, a sintaxe da linguagem Clojure é construída em expressões simbólicas que são primeiramente analisadas em estruturas de dados por um leitor, antes de serem efetivamente compiladas. O leitor da linguagem Clojure suporta a sintaxe literal para mapas, conjuntos e vetores, além de listas, e estes são compilados para as estruturas citadas diretamente. Clojure é um Lisp-1 e não se destina a ser um código compatível com outros dialetos da linguagem Lisp, uma vez que utiliza o seu próprio conjunto de estruturas de dados não compatíveis com outros Lisps.
Como um dialeto Lisp, Clojure suporta funções como objetos de primeira classe, um console interpretador (repl), e um sistema de macros. O sistema de macros da linguagem Clojure é muito semelhante ao usado em Common Lisp, com a excepção de que a versão Clojure da crase (chamado "sintaxe de quote") associa símbolos com seu namespace. Isso ajuda a evitar a captura não intencional de um nome, já que associar nomes de namespaces qualificados é proibido na linguagem. É possível forçar a captura de uma expansão de macro, mas isso deve ser feito de forma explícita. A linguagem Clojure não permite macros de leitura definidas pelo usuário, mas o leitor suporta uma forma mais restrita de extensão sintática. Clojure suporta multimétodos e para abstrações semelhantes a interfaces existe um protocolo baseado em polimorfismo e um sistema de tipos de dados usando registros, fornecendo alto desempenho e polimorfismo dinâmico concebido para evitar problemas de expressão.
Clojure tem suporte para sequências preguiçosas (lazy sequences) e incentiva o princípio da imutabilidade e estruturas de dados persistentes. Como uma linguagem funcional, a ênfase é colocada sobre recursão e em funções de alta ordem (higher-order functions) em vez de loops baseados em efeitos colaterais típicos do paradigma POO. A otimização de chamada de cauda (tail call optimization) automática não é suportada já que própria JVM não suporta o recurso nativamente; é possível fazê-la explicitamente usando a palavra-chave recur. Para a programação paralela e simultânea Clojure fornece software de memória transacional, um sistema agente reativo e programação concorrente baseada em canais.
Recentemente Clojure introduziu leitores condicionais, permitindo a incorporação de código Clojure e ClojureScript no mesmo namespace. Transdutores foram adicionados como uma maneira de compor as transformações. Transdutores permitem que funções de alta ordem, tais como map e fold possam ser generalizadas, operando sobre qualquer fonte de dados de entrada. Como tradicionalmente estas funções operam em sequências os transdutores permitem que as mesmas trabalhem em canais e também permitem que o usuário possa definir seus próprios modelos de transdução.
Plataformas e popularidade
editarA plataforma primária da linguagem Clojure é a JVM, mas existem outras implementações. As mais notáveis entre elas são a ClojureScript[4], que compila para JavaScript, e ClojureCLR[3], uma conversão completa para a CLR interoperável com o ecossistema .NET. Uma pesquisa da comunidade Clojure com 1.060 entrevistados realizado em 2013 descobriu que 47% dos inquiridos utilizaram tanto Clojure quanto ClojureScript ao trabalhar com a linguagem. Em 2014 esse número tinha aumentado para 55%. Projetos populares usando ClojureScript incluem implementações da biblioteca React como Reagent e Om.
Clojure também tem sido utilizado para a computação criativa, incluindo a arte visual, música, jogos e poesia.
Variações da linguagem Clojure têm sido desenvolvidas para plataformas diferentes das indicadas acima:
- las3r, um subconjunto de Clojure que é executado no ActionScript Virtual Machine (a plataforma Adobe Flash Player)
- clojure-py, uma implementação do Clojure em Python puro
- rouge, uma implementação do Clojure rodando na YARV em Ruby
- CljPerl, uma implementação do Clojure em Perl.
- Pixie, um dialeto Lisp inspirado na linguagem Clojure e escrito em RPython.
Exemplos de código
editar(println "Olá Mundo!")
Definindo uma função:
(defn quadrado [x]
(* x x))
"Olá, mundo" visual chamando a biblioteca Java Swing:
(javax.swing.JOptionPane/showMessageDialog nil "Olá Mundo" )
Unicode (Olá 世 ("Mundo") usando o suporte para ideogramas):
(println (str "Olá, " \u4e16)) ; exibindo no console
(javax.swing.JOptionPane/showMessageDialog nil (str "Olá, " \u4e16 "!")); Usando swing (modo gráfico)
Um gerador de números únicos thread-safe (embora, como muitos outros dialetos Lisp, Clojure tem uma função gensym integrada que é usada internamente):
(def i (atom 0))
(defn generate-unique-id
"Retorna uma identificação numérica distinta para cada chamada."
(swap! i inc))
Uma subclasse anônima de java.io.Writer que não escreve qualquer coisa, e uma macro para silenciar todas as impressões internamente:
(def bit-bucket-writer
(proxy [java.io.Writer]
(write [buf] nil)
(close nil)
(flush nil)))
(defmacro noprint
"Executa todas as expressões enviadas mas silencia qualquer impressão para o *out*"
[& forms]
`(binding [*out* bit-bucket-writer]
~@forms))
(noprint
(println "Olá, ninguém!"))
10 threads manipulando uma estrutura de dados comum, que consiste de 100 vetores cada um contendo 10 números únicos (inicialmente sequenciais). Cada thread em seguida, seleciona repetidamente duas posições aleatórias em dois vetores aleatórios e inverte sua posição. Todas as alterações nos vetores ocorrem em transações, fazendo uso de sistema de memória transacional da linguagem.
(defn run [nvecs nitems nthreads niters]
(let [vec-refs (→ (range (* nvecs nitems)) (partition nitems) (map (comp ref vec)) vec)
swap #(let [v1 (rand-int nvecs)
v2 (rand-int nvecs)
i1 (rand-int nitems)
i2 (rand-int nitems)]
(dosync
(let [tmp (nth @(vec-refs v1) i1)]
(alter (vec-refs v1) assoc i1 (nth @(vec-refs v2) i2))
(alter (vec-refs v2) assoc i2 tmp))))
report #(let [derefed (map deref vec-refs)]
(prn derefed)
(println "Distinct:" (→ derefed (apply concat) distinct count)))]
(report)
(dorun (apply pcalls (repeat nthreads #(dotimes [_ niters] (swap)))))
(report)))
(run 100 10 10 100000)
Saída do exemplo anterior:
([0 1 2 3 4 5 6 7 8 9] [10 11 12 13 14 15 16 17 18 19] ... [990 991 992 993 994 995 996 997 998 999]) Distinct: 1000
([382 318 466 963 619 22 21 273 45 596] [808 639 804 471 394 904 952 75 289 778] ... [484 216 622 139 651 592 379 228 242 355]) Distinct: 1000
Referências
- ↑ a b «Clojure inventor Hickey now aims for Android». InfoWorld. Consultado em 19 de fevereiro de 2016
- ↑ «Clojure». clojure.org. Consultado em 19 de fevereiro de 2016
- ↑ a b «Clojure - Clojure CLR». clojure.org. Consultado em 20 de fevereiro de 2016
- ↑ a b «Clojure - ClojureScript». clojure.org. Consultado em 20 de fevereiro de 2016
- ↑ a b «JIRA workflow - Clojure Community - Clojure Development». dev.clojure.org. Consultado em 23 de fevereiro de 2016
- ↑ «A New Era of Application Services at Puppet Labs». Puppet Labs (em inglês). Consultado em 19 de fevereiro de 2016
- ↑ Halloway, Stuart (23 de julho de 2020). «Cognitect Joins Nubank». Cognitect Blog (em inglês). Consultado em 24 de julho de 2020
- ↑ «Clojure - License». clojure.org. Consultado em 19 de fevereiro de 2016
- ↑ «Contributing FAQ - Clojure Community - Clojure Development». dev.clojure.org. Consultado em 19 de fevereiro de 2016
- ↑ «Clojure - Functional Programming». clojure.org. Consultado em 19 de fevereiro de 2016
- ↑ «Clojure - Hosted on the JVM». clojure.org. Consultado em 19 de fevereiro de 2016