close

Palhaço

Ir para a navegação Ir para a pesquisa
palhaço
Clojure logo.svg
Desenvolvedor(es)
Richard Hickey
https://clojure.org/
Informações gerais
Extensões comuns clj, cljs, cljc, edn e cljr
Paradigma Linguagem de programação funcional e multiparadigma
Apareceu em 2007
Desenhado por Chupão Rico
Última versão estável (2022-03-22)
tipo de sistema dinâmico , forte
implementações JVM , CLR , JavaScript
influenciado por Lisp , ML , Haskell , Erlang Prolog
Sistema operativo Multi plataforma
Licença Licença Pública Eclipse

Clojure é um dialeto de linguagem de programação de propósito geral de Lisp . Coloca uma ênfase especial no paradigma funcional , com o objetivo (entre outros) de remover a complexidade associada à programação concorrente . O Clojure pode ser executado na máquina virtual Java e na máquina virtual da plataforma .NET , bem como compilado para JavaScript .

Princípios

Rich Hickey descreve o desenvolvimento do Clojure como uma busca por uma linguagem que ele não conseguia encontrar: um lisp funcional por padrão, construído sobre um ambiente robusto ao invés de sua própria plataforma, e com programação concorrente em mente. [ 1 ]

Da mesma forma, a orientação a objetos é rejeitada em princípio, oferecendo uma abordagem na qual os programas são expressos como a aplicação de funções em dados, e não como a interação entre entidades mutáveis ​​que misturam representação de dados e comportamento. Por outro lado, recursos como instanciabilidade, polimorfismo e interfaces são efetivamente parte da linguagem.

Sintaxe

Como o resto da família Lisp, a sintaxe do Clojure é construída em expressões simbólicas que são convertidas em estruturas de dados por um leitor antes de serem compiladas. As expressões são caracterizadas por serem delimitadas por parênteses, e por sua notação de prefixo, pela qual o primeiro membro de cada lista é chamado como função, passando o restante dos membros como argumentos.

Essa peculiaridade, estranha para quem está acostumado às linguagens mais populares baseadas na sintaxe da linguagem de programação C, é a base de sua flexibilidade. Estruturas de dados como mapas , conjuntos e vetores têm uma expressão literal; eles não requerem nenhuma transformação ao serem incorporados na árvore sintática gerada pelo compilador. Clojure é um Lisp-1 e não foi especialmente projetado para ser compatível com outros lisp .

Macro

Uma macro é um pedaço de código que aceita outras expressões como argumentos, sem avaliá-las, transformando-as antes de avaliá-las. Isso permite o surgimento de "programas criando programas": acréscimos à linguagem - estruturas de controle de fluxo - ou criação de uma linguagem específica de domínio . Possibilidades em princípio não alcançáveis ​​em outras famílias linguísticas sem recorrer ao desenvolvimento de um compilador .

O sistema de macros do Clojure é muito semelhante ao do Common Lisp , com a exceção de que a versão do Clojure do backquote (chamado de "aspas sintáticas") qualifica os símbolos com o namespace ao qual eles pertencem. Isso ajuda a evitar a captura não intencional, pois as ligações qualificadas por nome são proibidas. É possível forçar a expansão de uma macro que os capture, mas isso deve ser feito explicitamente. Clojure também proíbe a religação de nomes globais em outros namespaces que foram importados para o atual.

Outra característica da citação sintática é que ela permite um sistema de modelagem , no qual você pode especificar quais membros de uma lista devem ser avaliados usando os operadores unquote (~) e unquote-splice (~@), levando a macros mais concisas e gerenciável.

Recursos de idioma

  • Desenvolvimento dinâmico com um console de avaliação ( REPL: read eval print loop ).
  • Representação de funções como valores e preferência por recursão e uso de funções de ordem superior sobre iteração com base em efeitos colaterais .
  • Números de precisão arbitrária e representação literal de frações, gerados em divisões não inteiras.
  • Sequências com avaliação lenta (os elementos da sequência não são computados até que sejam necessários, o que permite representar conjuntos potencialmente infinitos).
  • Sistema integrado de estruturas de dados persistentes e imutáveis.
  • Controle de estado (conjunto de valores que uma entidade pode adquirir ao longo do tempo) em situações de simultaneidade por meio de sistemas transacionais, agentes e por meio de ligações locais .
  • Interação com java : Ao serem compilados em bytecode JVM , aplicativos escritos em Clojure podem ser facilmente integrados em servidores de aplicativos ou outros ambientes Java com pouca complexidade adicional. Todas as interfaces possíveis na classe, estrutura de dados e nível de simultaneidade são implementadas por padrão para minimizar os esforços necessários para alcançar essa portabilidade.

Exemplos

Olá mundo . Observe que, devido à natureza do REPL, um comando de impressão não é necessário .

"Olá mundo!"

Um gerador de números único e consecutivo que suporta chamadas simultâneas:

( let  [i  ( atom  0 ) ] 
  ( defn  generate-unique-id 
    "Retorna um identificador numérico diferente para cada chamada." 
    [] 
    ( swap!  i  inc )))

Uma subclasse anônima java.io.Writerdisso não escreve em lugar nenhum, e uma macro que a usa para silenciar todas as expressões avaliadas com ela.

( def  bit-bucket-writer 
  ( proxy  [java.io.Writer]  [] 
    ( write  [buf]  nil ) 
    ( close  []     nil ) 
    ( flush  []     nil )))

( defmacro  noprint 
  "Avalia a expressão dada com todas as impressões para *out* silenciadas."   
  [&  forms] 
  ` ( binding  [*out*  bit-bucket-writer] 
     ~@forms ))

( noprint 
 ( println  "Olá, ninguém!" ))

Neste exemplo, dez threads manipulam uma estrutura de dados compartilhada, que consiste em cem vetores contendo dez números únicos de início sequencial. Cada thread escolhe duas posições aleatórias em dois vetores aleatórios e as troca. Todas as alterações nos vetores são feitas nas transações usando o sistema de memória transacional do software Clojure . É por isso que mesmo após mil iterações nenhum número é perdido.

( defn  run  [nvecs  nitems  nthreads  niters] 
  ( let  [vec-refs  ( vec  ( map  ( comp  ref  vec ) 
                           ( partição  nitems  ( range  ( *  nvecs  nitems )))))) 
        swap  #( let  [v1  ( rand-int  nvecs ) 
                    v2  ( rand-int  nvecs ) 
                    i1  ( rand-int  nitems ) 
                    i2  ( rand-int  nitems ) ] 
                ( dosync 
                 ( let  [temp  ( nth  @ ( vec-refs  v1 )  i1 ) ] 
                   ( alter  ( vec-refs  v1 )  assoc  i1  ( nth  @ ( vec-refs  v2 )  i2 )) 
                   ( alter  ( vec-refs  v2 )  assoc  i2  temp )))) 
        report  #( do 
                 ( prn  ( map  deref  vec-refs )) 
                 ( println  "Distinct:" 
                          ( count  ( distinct  ( apply  concat  ( map  deref  vec-refs )))))) ] 
    ( report ) 
    ( dorun  ( apply  pcalls  ( repeat  nthreads  #( dotimes  [_  niters]  ( swap ))))) 
    ( report )))

( executar  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] ) 
Distinto:  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 ] )
 

Bibliografia

Links externos

Referências

  1. ^ "Princípios fundamentais" . Rich Hickey (em inglês) . Recuperado em 2008-10-17 isto não tem paradigma .