Clojure - Clojure
Paradigma | multiparadigma : |
---|---|
Família | Lisp |
Projetado por | Rich Hickey |
Apareceu pela primeira vez | 2007 |
Versão estável | 1.10.3 / 4 de março de 2021
|
Disciplina de digitação | |
Plataforma | |
Licença | Licença Pública Eclipse |
Extensões de nome de arquivo |
|
Local na rede Internet | clojure |
Influenciado por | |
Influenciado | |
|
Clojure ( / k l oʊ ʒ ər / , como fechamento ) é uma dinâmica e funcional dialeto da linguagem de programação Lisp no Java plataforma. Como outros dialetos Lisp, Clojure trata o código como dados e tem um sistema de macro Lisp . O processo de desenvolvimento atual é conduzido pela comunidade , supervisionado por Rich Hickey como seu benevolente ditador vitalício (BDFL).
Clojure defende imutabilidade e estruturas de dados imutáveis e encoraja os programadores a serem explícitos sobre o gerenciamento de identidade e seus estados. Esse foco na programação com valores imutáveis e construções explícitas de progressão no tempo tem como objetivo facilitar o desenvolvimento de programas mais robustos, especialmente simultâneos , que são simples e rápidos. Embora seu sistema de tipo seja inteiramente dinâmico , esforços recentes também buscaram a implementação de um sistema de tipo dependente .
O suporte comercial para Clojure é fornecido pela empresa Cognitect, que patrocina uma conferência promocional.
História e processo de desenvolvimento
Rich Hickey é o criador da linguagem Clojure. Antes de Clojure, ele desenvolveu dotLisp, um projeto semelhante baseado na plataforma .NET , e três tentativas anteriores de fornecer interoperabilidade entre Lisp e Java : uma interface de linguagem estrangeira Java para Common Lisp (jfli), Uma Interface de Objeto Estrangeiro para Lisp (FOIL) e uma interface amigável com Lisp para Servlets Java (Lisplets).
Hickey passou cerca de 2 anos e meio trabalhando no Clojure antes de lançá-lo publicamente, grande parte desse tempo trabalhando exclusivamente no Clojure sem nenhum financiamento externo. No final desse tempo, Hickey enviou um e-mail anunciando o idioma para alguns amigos da comunidade Common Lisp.
O processo de desenvolvimento é conduzido pela comunidade e gerenciado na página do projeto Clojure JIRA . A discussão geral sobre o desenvolvimento ocorre no Clojure Google Group. Qualquer pessoa pode enviar problemas e ideias em ask.clojure.org, mas para contribuir com patches, é necessário assinar o contrato de Contribuidor do Clojure. Os problemas do JIRA são processados por uma equipe de analistas e, finalmente, Rich Hickey aprova as alterações.
O nome de Clojure, de acordo com Hickey, é um jogo de palavras no conceito de programação " closure " incorporando as letras C, L e J para C # , Lisp e Java respectivamente - três linguagens que tiveram uma grande influência no design de Clojure.
Filosofia de design
Rich Hickey desenvolveu o Clojure porque queria um Lisp moderno para programação funcional , simbiótico com a plataforma Java estabelecida e projetado para simultaneidade .
A abordagem de Clojure ao estado é caracterizada pelo conceito de identidades, que são representadas como uma série de estados imutáveis ao longo do tempo. Como os estados são valores imutáveis, qualquer número de trabalhadores pode operar neles em paralelo, e a simultaneidade se torna uma questão de gerenciar as mudanças de um estado para outro. Para este propósito, Clojure fornece vários tipos de referência mutáveis , cada um com uma semântica bem definida para a transição entre estados.
Visão geral da linguagem
Versão | Data de lançamento | Principais recursos / melhorias |
---|---|---|
16 de outubro de 2007 | Lançamento público inicial | |
1.0 | 4 de maio de 2009 | Primeira versão estável |
1,1 | 31 de dezembro de 2009 | Futuros |
1,2 | 19 de agosto de 2010 | Protocolos |
1,3 | 23 de setembro de 2011 | Suporte primitivo aprimorado |
1,4 | 15 de abril de 2012 | Literais do leitor |
1,5 | 1 de Março de 2013 | Redutores |
1.5.1 | 10 de março de 2013 | Corrigindo um vazamento de memória |
1,6 | 25 de março de 2014 | API Java, algoritmos de hash aprimorados |
1,7 | 30 de junho de 2015 | Transdutores, condicionais de leitor |
1,8 | 19 de janeiro de 2016 | Funções de string adicionais, link direto, servidor de soquete |
1,9 | 8 de dezembro de 2017 | Integração com especificações, ferramentas de linha de comando |
1,10 | 17 de dezembro de 2018 | Relatório de erros aprimorado, compatibilidade com Java |
1,10.1 | 6 de junho de 2019 | Trabalhar em torno de uma regressão de desempenho Java e melhorar o relatório de erros de clojure.main
|
1,10.2 | 26 de janeiro de 2021 | Melhorias de interoperabilidade / compatibilidade Java e outras correções de linguagem importantes |
1.10.3 | 4 de março de 2021 | suporte prepl para condicionais de leitor |
Última versão
|
Clojure é executado na plataforma Java e, como resultado, integra-se com Java e oferece suporte total à chamada de código Java de Clojure, e o código Clojure também pode ser chamado de Java. A comunidade usa ferramentas como Leiningen para automação de projetos, fornecendo suporte para integração Maven . Leiningen lida com o gerenciamento de pacotes de projeto e dependências e é configurado usando a sintaxe Clojure.
Como a maioria dos outros Lisps, a sintaxe de Clojure é construída em expressões S que são primeiro analisadas em estruturas de dados por um leitor antes de serem compiladas. O leitor de Clojure suporta sintaxe literal para mapas , conjuntos e vetores , além de listas, e estes são compilados diretamente nas estruturas mencionadas. Clojure é um Lisp-1 e não se destina a ser compatível com o código de outros dialetos do Lisp, uma vez que usa seu próprio conjunto de estruturas de dados incompatíveis com outros Lisps.
Como um dialeto Lisp, Clojure suporta funções como objetos de primeira classe , um loop de leitura-eval-impressão (REPL) e um sistema de macro. O sistema de macro Lisp de Clojure é muito semelhante ao de Common Lisp, com a exceção de que a versão de Clojure da crase (denominada "aspas de sintaxe") qualifica símbolos com seu espaço de nomes . Isso ajuda a evitar a captura de nome não intencional, pois a vinculação a nomes qualificados por namespace é proibida. É possível forçar uma expansão da macro de captura, mas isso deve ser feito explicitamente. Clojure não permite macros de leitor definidas pelo usuário, mas o leitor oferece suporte a uma forma mais restrita de extensão sintática. Clojure suporta multimétodos e para abstrações do tipo interface possui um polimorfismo baseado em protocolo e sistema de tipo de dados usando registros , fornecendo alto desempenho e polimorfismo dinâmico projetado para evitar o problema de expressão .
Clojure tem suporte para sequências preguiçosas e incentiva o princípio de imutabilidade e estruturas de dados persistentes . Como uma linguagem funcional , a ênfase é colocada em funções de recursão e de ordem superior, em vez de looping baseado em efeitos colaterais. A otimização automática da chamada final não é suportada porque a JVM não a suporta nativamente; é possível fazer isso explicitamente usando a recur
palavra - chave. Para programação paralela e simultânea , o Clojure fornece memória transacional de software , um sistema de agente reativo e programação simultânea baseada em canal .
Clojure 1.7 introduziu condicionais de leitor, permitindo a incorporação de código Clojure e ClojureScript no mesmo namespace. Transdutores foram adicionados como um método de composição de transformações. Os transdutores permitem funções de ordem superior, como mapear e dobrar, para generalizar sobre qualquer fonte de dados de entrada. Embora tradicionalmente essas funções operem em sequências , os transdutores permitem que elas trabalhem em canais e permitem que o usuário defina seus próprios modelos de transdução.
Plataformas alternativas
A plataforma principal do Clojure é Java , mas existem outras implementações de destino. O mais notável deles é ClojureScript, que compila para ECMAScript 3, e ClojureCLR, uma porta completa na plataforma .NET , interoperável com seu ecossistema. Uma pesquisa da comunidade Clojure com 1.060 entrevistados realizada em 2013 descobriu que 47% dos entrevistados usavam Clojure e ClojureScript ao trabalhar com Clojure. Em 2014 esse número havia aumentado para 55%, em 2015, com base em 2.445 respondentes, para 66%. Os projetos populares do ClojureScript incluem implementações da biblioteca React , como Reagent, re-frame, Rum e Om.
Outras Implementações
Outras implementações de Clojure em diferentes plataformas incluem:
- CljPerl, Clojure no topo do Perl
- Clojerl, Clojure no BEAM , a máquina virtual Erlang
- clojure-py, Clojure em Python puro
- Ferret, compila em C ++ 11 independente que pode ser executado em microcontroladores
- Joker, intérprete e linter escrito em Go
- Las3r, um subconjunto do Clojure executado na máquina virtual ActionScript (a plataforma Adobe Flash Player)
- Pixie, dialeto Lisp inspirado em Clojure escrito em RPython
- Rouge, Clojure no topo de YARV em Ruby
Popularidade
Com o interesse contínuo em programação funcional, a adoção de Clojure por desenvolvedores de software que usam a plataforma Java continuou a aumentar. A linguagem também foi recomendada por desenvolvedores de software como Brian Goetz, Eric Evans, James Gosling , Paul Graham e Robert C. Martin . A ThoughtWorks , ao avaliar linguagens de programação funcionais para seu Radar de Tecnologia, descreveu Clojure como "uma implementação simples e elegante de Lisp no JVM" em 2010 e promoveu seu status para "ADOPTAR" em 2012.
No "JVM Ecosystem Report 2018" (que foi afirmado ser "a maior pesquisa de todos os desenvolvedores Java"), que foi preparado em colaboração por Snyk e Java Magazine, classificou Clojure como a 2ª linguagem de programação mais usada na JVM para " principais aplicações ". Clojure é usado na indústria por empresas como Apple , Atlassian , Funding Circle , Netflix , Puppet e Walmart , bem como agências governamentais como a NASA . Também tem sido usado para computação criativa, incluindo artes visuais, música, jogos e poesia.
Ferramentas
O ferramental para o desenvolvimento de Clojure teve uma melhora significativa ao longo dos anos. A seguir está uma lista de alguns IDEs populares e editores de texto com plug-ins que adicionam suporte para programação em Clojure:
- Átomo , com cloro
- Emacs , com CIDER
- IntelliJ IDEA , com Clojure-Kit ou Cursive (uma licença gratuita está disponível para uso não comercial )
- Mesa de Luz
- Vim , com lareira.vim, vim-iced ou Conjure (apenas Neovim)
- Código do Visual Studio , com Calva ou Clover
Além das ferramentas fornecidas pela comunidade, as ferramentas oficiais da CLI do Clojure também estão disponíveis no Linux , macOS e Windows desde o Clojure 1.9.
Recursos por exemplo
Os exemplos a seguir podem ser executados em um Clojure REPL, como um iniciado com as ferramentas Clojure CLI, ou um REPL online, como um disponível em REPL.it.
Simplicidade
Devido à forte ênfase na simplicidade, os programas Clojure típicos consistem principalmente em funções e estruturas de dados simples (ou seja, listas, vetores, mapas e conjuntos):
;; A typical entry point of a Clojure program:
;; `-main` function
(defn -main ; name
[& args] ; (variable) parameters
(println "Hello, World!")) ; body
Programação no REPL
Como outros Lisps , um dos recursos icônicos do Clojure é a programação interativa no REPL . Observe que, nos exemplos a seguir, ;
inicia um comentário de linha e ;; =>
indica a saída esperada:
; define a var
(def a 42)
;; => #'user/a
; call a function named `+`
(+ a 8)
;; => 50
; call a function named `even?`
(even? a)
;; => true
; define a function that returns the remainder of `n` when divided by 10
(defn foo [n] (rem n 10))
;; => #'user/foo
; call the function
(foo a)
;; => 2
; print the docstring of `rem`
(doc rem)
;; =>
-------------------------
clojure.core/rem
([num div])
remainder of dividing numerator by denominator.
; print the source of `rem`
(source rem)
;; =>
(defn rem
"remainder of dividing numerator by denominator."
{:added "1.0"
:static true
:inline (fn [x y] `(. clojure.lang.Numbers (remainder ~x ~y)))}
[num div]
(. clojure.lang.Numbers (remainder num div)))
Nomes em tempo de execução
Ao contrário de outros ambientes de tempo de execução onde os nomes são compilados, o ambiente de tempo de execução do Clojure é facilmente introspectivo usando estruturas de dados normais do Clojure:
; define a var
(def a 42)
;; => #'user/a
; get a map of all public vars interned in the `user` namespace
(ns-publics 'user)
;; => {a #'user/a}
; reference the var via `#'` (reader macro) and
; its associated, namespace-qualified symbol `user/a`
#'user/a
;; => #'user/a
; de-reference (get the value of) the var
(deref #'user/a)
;; => 42
; define a function (with a docstring) that
; returns the remainder of `n` when divided by 10
(defn foo "returns `(rem n 10)`" [n] (rem n 10))
;; => #'user/foo
; get the metadata of the var `#'user/foo`
(meta #'user/foo)
;; =>
{:arglists ([n]),
:doc "returns `(rem n 10)`",
:line 1,
:column 1,
:file "user.clj",
:name foo,
:ns #namespace[user]}
Codifique como dados (homoiconicidade)
Semelhante a outros Lisps , Clojure é homoicônico (também conhecido como "código como dados"). No exemplo abaixo, podemos ver como escrever código que modifica o próprio código:
; call a function (code)
(+ 1 1)
;; => 2
; quote the function call
; (turning code into data, which is a list of symbols)
(quote (+ 1 1))
;; => (+ 1 1)
; get the first element on the list
; (operating on code as data)
(first (quote (+ 1 1)))
;; => +
; get the last element on the list
; (operating on code as data)
(last (quote (+ 1 1)))
;; => 1
; get a new list by replacing the symbols on the original list
; (manipulating code as data)
(map (fn [form]
(case form
1 'one
+ 'plus))
(quote (+ 1 1)))
;; => (plus one one)
Operadores expressivos para transformação de dados
As macros de threading ( ->
, ->>
e amigos) podem expressar sintaticamente a abstração de canalizar uma coleção de dados por meio de uma série de transformações:
(->> (range 10)
(map inc)
(filter even?))
;; => (2 4 6 8 10)
Isso também pode ser alcançado de forma mais eficiente usando transdutores:
(sequence (comp (map inc)
(filter even?))
(range 10))
;; => (2 4 6 8 10)
Gerenciamento seguro de thread de identidade e estado
Um gerador thread-safe de números de série exclusivos (embora, como muitos outros dialetos Lisp, Clojure tenha uma gensym
função embutida que usa internamente):
(def i (atom 0))
(defn generate-unique-id
"Returns a distinct numeric ID for each call."
[]
(swap! i inc))
Macros
Uma subclasse anônima de java.io.Writer
que não grava em nada, e uma macro usando isso para silenciar todas as impressões dentro dela:
(def bit-bucket-writer
(proxy [java.io.Writer] []
(write [buf] nil)
(close [] nil)
(flush [] nil)))
(defmacro noprint
"Evaluates the given `forms` with all printing to `*out*` silenced."
[& forms]
`(binding [*out* bit-bucket-writer]
~@forms))
(noprint
(println "Hello, nobody!"))
;; => nil
Interoperabilidade de linguagem com Java
Clojure foi criado desde o início para abraçar suas plataformas host como um de seus objetivos de design e, portanto, fornece excelente interoperabilidade de linguagem com Java:
; call an instance method
(.toUpperCase "apple")
;; => "APPLE"
; call a static method
(System/getProperty "java.vm.version")
;; => "12+33"
; create an instance of `java.util.HashMap` and
; add some entries
(doto (java.util.HashMap.)
(.put "apple" 1)
(.put "banana" 2))
;; => {"banana" 2, "apple" 1}
; create an instance of `java.util.ArrayList` and
; increment its elements with `clojure.core/map`
(def al (doto (java.util.ArrayList.)
(.add 1)
(.add 2)
(.add 3)))
(map inc al)
;; => (2 3 4)
; show a message dialog using Java Swing
(javax.swing.JOptionPane/showMessageDialog
nil
"Hello, World!")
;; => nil
Memória transacional de software
10 threads manipulando uma estrutura de dados compartilhada, que consiste em 100 vetores, cada um contendo 10 (inicialmente sequenciais) números exclusivos. Cada thread então seleciona repetidamente duas posições aleatórias em dois vetores aleatórios e os troca. Todas as mudanças nos vetores ocorrem nas transações, fazendo uso do sistema de memória transacional do software Clojure :
(defn run
[nvecs nitems nthreads niters]
(let [vec-refs
(->> (* nvecs nitems)
(range)
(into [] (comp (partition-all nitems)
(map vec)
(map ref))))
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
#(->> vec-refs
(into [] (comp (map deref)
(map (fn [v] (prn v) v))
cat
(distinct)))
(count)
(println "Distinct:"))]
(report)
(->> #(dotimes [_ niters] (swap))
(repeat nthreads)
(apply pcalls)
(dorun))
(report)))
(run 100 10 10 100000)
;; =>
[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
nil
Veja também
Referências
Leitura adicional
- Sotnikov, Dmitri (2020), Web Development with Clojure (3rd ed.), Pragmatic Bookshelf , ISBN 978-1-68050-682-2
- Olsen, Russ (2018), Getting Clojure , Pragmatic Bookshelf , ISBN 978-1-68050-300-5
- Miller, Alex; Halloway, Stuart; Bedra, Aaron (2018), Programming Clojure (3ª ed.), Pragmatic Bookshelf , ISBN 978-1-68050-246-6
- Rathore, Amit; Avila, Francis (2015), Clojure in Action (2ª ed.), Manning , ISBN 978-1-61729-152-4
- Higginbotham, Daniel (2015), Clojure for the Brave and True , No Starch Press , ISBN 978-1-59327-591-4
- Gamble, Julian (2015), Clojure Recipes , Pearson Publishing , ISBN 978-0-32192-773-6
- Vandgrift, Ben; Miller, Alex (2015), Clojure Applied , Pragmatic Bookshelf , ISBN 978-1-68050-074-5
- Rochester, Eric (2015), Clojure Data Analysis Cookbook (2ª ed.), Packt Publishing , ISBN 978-1-78439-029-7
- Fogus, Michael; Houser, Chris (2014), The Joy of Clojure (2ª ed.), Manning , ISBN 978-1-617291-41-8
- Kelker, Ryan (2013), Clojure for Domain-specific Languages , Packt Publishing , ISBN 978-1-78216-650-4
- Rochester, Eric (2014), Mastering Clojure Data Analysis , Packt Publishing , ISBN 978-1-78328-413-9
- Emerick, Chas; Carper, Brian; Grand, Christophe (19 de abril de 2012), Clojure Programming , O'Reilly Media , ISBN 978-1-4493-9470-7
- VanderHart, Luke; Sierra, Stuart (7 de junho de 2010), Practical Clojure , Apress , ISBN 978-1-4302-7231-1
links externos
1955 | 1960 | 1965 | 1970 | 1975 | 1980 | 1985 | 1990 | 1995 | 2000 | 2005 | 2010 | 2015 | 2020 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
LISP 1, 1.5, LISP 2 (abandonado) | ||||||||||||||
Maclisp | ||||||||||||||
Interlisp | ||||||||||||||
MDL (linguagem de programação) | ||||||||||||||
Lisp Máquina Lisp | ||||||||||||||
Esquema | R5RS | R6RS | R7RS pequeno | |||||||||||
NADA | ||||||||||||||
ZIL (linguagem de implementação Zork) | ||||||||||||||
Franz Lisp | ||||||||||||||
Lisp Comum | ||||||||||||||
Le Lisp | ||||||||||||||
T | ||||||||||||||
Esquema Chez | ||||||||||||||
Emacs Lisp | ||||||||||||||
AutoLISP | ||||||||||||||
PicoLisp | ||||||||||||||
EuLisp | ||||||||||||||
ISLISP | ||||||||||||||
OpenLisp | ||||||||||||||
Esquema PLT | Raquete | |||||||||||||
GNU Guile | ||||||||||||||
Visual LISP | ||||||||||||||
Clojure | ||||||||||||||
Arco | ||||||||||||||
LFE | ||||||||||||||
Hy |