Clojure - Guia rápido

Clojure é uma linguagem de programação funcional dinâmica de alto nível. Clojure é projetado com base na linguagem de programação LISP e tem compiladores que o tornam rodando em Java e em ambientes de execução .Net.

Antes de falarmos sobre Clojure, vamos apenas ter uma descrição rápida da linguagem de programação LISP. Os LISPs têm um pequeno núcleo de linguagem, quase nenhuma sintaxe e um recurso de macro poderoso. Com esses recursos, você pode dobrar o LISP para atender ao seu projeto, em vez do contrário. O LISP existe há muito tempo, desde 1958.

O LISP comum lê uma expressão, avalia e então imprime o resultado. Por exemplo, se você quiser calcular o valor de uma expressão matemática simples de 4 + 6, digite.

USER(1) (+ 4 6)

Clojure tem os seguintes objetivos principais de alto nível como linguagem de programação.

  • É baseado na linguagem de programação LISP, o que torna suas declarações de código menores do que as linguagens de programação tradicionais.

  • É uma linguagem de programação funcional.

  • Ele se concentra na imutabilidade, que é basicamente o conceito de que você não deve fazer nenhuma alteração nos objetos criados no local.

  • Ele pode gerenciar o estado de um aplicativo para o programador.

  • Suporta simultaneidade.

  • Ele abrange linguagens de programação existentes. Por exemplo, Clojure pode fazer uso de todo o ecossistema Java para gerenciamento da execução do código por meio do JVM.

O site oficial do Clojure é https://clojure.org/

Existem várias maneiras de trabalhar com Clojure como linguagem de programação. Veremos duas maneiras de trabalhar com a programação Clojure.

  • Leiningen - Leiningen é uma ferramenta essencial para criar, construir e automatizar projetos Clojure.

  • Eclipse Plugin - Existe um plugin chamado CounterClockwise, que está disponível para Eclipse para realizar o desenvolvimento de Clojure no Eclipse IDE.

Instalação Leiningen

Certifique-se de que os seguintes requisitos do sistema sejam atendidos antes de prosseguir com a instalação.

Requisitos de sistema

JDK JDK 1.7 ou superior
Memória 2 GB de RAM (recomendado)

Step 1- Baixe a instalação binária. Vá para o linkhttp://leiningen-wininstallerpara obter o Windows Installer. Clique na opção para iniciar o download do instalador Groovy.

Step 2 - Inicie o instalador e clique no botão Avançar.

Step 3 - Especifique o local da instalação e clique no botão Avançar.

Step 4- A configuração detectará a localização de uma instalação Java existente. Clique no botão Avançar para prosseguir.

Step 5 - Clique no botão Instalar para iniciar a instalação.

Após a conclusão da instalação, você terá a opção de abrir um Clojure REPL, que é um ambiente que pode ser usado para criar e testar seus programas Clojure.

Instalação Eclipse

Certifique-se de que os seguintes requisitos do sistema sejam atendidos antes de prosseguir com a instalação.

Requisitos de sistema

JDK JDK 1.7 ou superior
Eclipse Eclipse 4.5 (Marte)

Step 1- Abra o Eclipse e clique no item Menu. Clique em Ajuda → Eclipse Marketplace.

Step 2- Digite a palavra-chave Clojure na caixa de diálogo que aparece e clique no botão 'Go'. A opção para sentido anti-horário aparecerá, clique no botão Instalar para iniciar a instalação deste plugin.

Step 3 - Na próxima caixa de diálogo, clique no botão Confirmar para iniciar a instalação.

Step 4- Na próxima caixa de diálogo, você será solicitado a aceitar o contrato de licença. Aceite o contrato de licença e clique no botão Concluir para continuar com a instalação.

A instalação começará e, depois de concluída, solicitará que você reinicie o Eclipse.

Depois que o Eclipse for reiniciado, você verá a opção no Eclipse para criar um novo projeto Clojure.

Para entender a sintaxe básica do Clojure, vamos primeiro examinar um programa simples Hello World.

Hello World como um programa completo

Escreva 'Olá, mundo' em um programa Clojure completo. A seguir está um exemplo.

Exemplo

(ns clojure.examples.hello
   (:gen-class))
(defn hello-world []
   (println "Hello World"))
(hello-world)

As seguintes coisas precisam ser observadas sobre o programa acima.

  • O programa será escrito em um arquivo chamado main.clj. A extensão 'clj' é o nome da extensão de um arquivo de código clojure. No exemplo acima, o nome do arquivo é main.clj.

  • A palavra-chave 'defn' é usada para definir uma função. Veremos as funções em detalhes em outro capítulo. Por enquanto, saiba que estamos criando uma função chamada helloworld, que terá nosso código Clojure principal.

  • Em nosso código Clojure, estamos usando a instrução 'println' para imprimir “Hello World” na saída do console.

  • Em seguida, chamamos a função hello-world que, por sua vez, executa a instrução 'println'.

O programa acima produz a seguinte saída.

Resultado

Hello World

Forma Geral de uma Declaração

A forma geral de qualquer instrução deve ser avaliada entre colchetes, conforme mostrado no exemplo a seguir.

(+ 1 2)

No exemplo acima, a expressão inteira está entre colchetes. A saída da instrução acima é 3. O operador + atua como uma função em Clojure, que é usado para a adição de numerais. Os valores de 1 e 2 são conhecidos como parameters to the function.

Vamos considerar outro exemplo. Neste exemplo, 'str' é o operador que é usado para concatenar duas strings. As strings “Hello” e “World” são usadas como parâmetros.

(str "Hello" "World")

Exemplo

Se combinarmos as duas instruções acima e escrevermos um programa, ele se parecerá com o seguinte.

(ns clojure.examples.hello
   (:gen-class))
(defn Example []
   (println (str "Hello World"))
   (println (+ 1 2)))
(Example)

Resultado

O programa acima produz a seguinte saída.

Hello World
3

Namespaces

Um namespace é usado para definir um limite lógico entre os módulos definidos no Clojure.

Namespace atual

Isso define o namespace atual no qual o código Clojure atual reside.

Sintaxe

*ns*

Exemplo

Na janela de comando REPL, execute o seguinte comando.

*ns*

Resultado

Quando executamos o comando acima, a saída será adiada dependendo de qual é o namespace atual. A seguir está um exemplo de uma saída. O namespace do código Clojure é -

clojure.examples.hello

(ns clojure.examples.hello
   (:gen-class))
(defn Example []
   (println (str "Hello World"))
   (println (+ 1 2)))
(Example)

Exigir declaração em Clojure

O código Clojure é empacotado em bibliotecas. Cada biblioteca Clojure pertence a um namespace, que é análogo a um pacote Java. Você pode carregar uma biblioteca Clojure com a instrução 'Require'.

Sintaxe

(require quoted-namespace-symbol)

Exemplo

A seguir está um exemplo do uso desta declaração.

(ns clojure.examples.hello
   (:gen-class))
(require ‘clojure.java.io’)
(defn Example []
   (.exists (file "Example.txt")))
(Example)

No código acima, estamos usando a palavra-chave 'require' para importar o namespace clojure.java.io que possui todas as funções necessárias para a funcionalidade de entrada / saída. Como não temos a biblioteca necessária, podemos usar a função 'arquivo' no código acima.

Comentários em Clojure

Os comentários são usados ​​para documentar seu código. Os comentários de uma única linha são identificados usando ;; em qualquer posição na linha. A seguir está um exemplo.

Exemplo

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (println "Hello World"))
(Example)

Delimitadores

No Clojure, as instruções podem ser divididas ou delimitadas usando colchetes ou colchetes.

Exemplo

A seguir estão dois exemplos.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (println (+ 1 2 3)))
(Example)

Resultado

O programa acima produz a seguinte saída.

6

Exemplo

A seguir está outro exemplo.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (println [+ 1 2 3]))
(Example)

Resultado

O programa acima produz a seguinte saída.

[#object[clojure.core$_PLUS_ 0x10f163b "clojure.core$_PLUS_@10f163b"] 1 2 3]

Espaços em branco

Os espaços em branco podem ser usados ​​no Clojure para dividir os diferentes componentes de uma instrução para maior clareza. Isso pode ser feito com a ajuda do operador vírgula (,).

Por exemplo, as duas instruções a seguir são equivalentes e a saída de ambas as instruções será 15.

(+ 1 2 3 4 5)
(+ 1, 2, 3, 4, 5)

Embora Clojure ignore vírgulas, às vezes as usa para tornar as coisas mais fáceis para o programador ler.

Por exemplo, se você tiver um mapa hash como o seguinte (def a-map {: a 1: b 2: c 3}) e solicitar seu valor na janela REPL, Clojure imprimirá a saída como {: a 1, : b 2,: c 3}.

Os resultados são mais fáceis de ler, especialmente se você estiver observando uma grande quantidade de dados.

Símbolos

No Clojure, os símbolos são equivalentes aos identificadores em outras linguagens de programação. Mas, ao contrário de outras linguagens de programação, o compilador vê os símbolos como valores de string reais. Como um símbolo é um valor, um símbolo pode ser armazenado em uma coleção, passado como um argumento para uma função, etc., assim como qualquer outro objeto.

Um símbolo pode conter apenas caracteres alfanuméricos e '* +! /. : - _? ' mas não deve começar com um numeral ou dois pontos.

A seguir estão exemplos válidos de símbolos.

tutorial-point!
TUTORIAL
+tutorial+

Estrutura do Projeto Clojure

Finalmente, vamos falar sobre uma estrutura de projeto típica para um projeto Clojure. Como o código do Clojure é executado na máquina virtual Java, a maior parte da estrutura do projeto no Clojure é semelhante ao que você encontraria em um projeto Java. A seguir está o instantâneo de uma estrutura de projeto de amostra no Eclipse para um projeto Clojure.

As seguintes coisas importantes precisam ser observadas sobre a estrutura do programa acima.

  • demo_1 - Este é o pacote no qual o arquivo de código Clojure é colocado.

  • core.clj - Este é o arquivo de código principal do Clojure, que conterá o código para o aplicativo Clojure.

  • A pasta Leiningen contém arquivos como clojure-1.6.0.jar, necessários para executar qualquer aplicativo baseado em Clojure.

  • O arquivo pom.properties conterá informações como groupId, artifactId e versão do projeto Clojure.

  • O arquivo project.clj contém informações sobre o próprio aplicativo Clojure. A seguir está um exemplo do conteúdo do arquivo de projeto.

(defproject demo-1 "0.1.0-SNAPSHOT"
   :description "FIXME: write description"
   :url "http://example.com/FIXME"
   :license {
      :name "Eclipse Public License"
      :url "http://www.eclipse.org/legal/epl-v10.html"
   }
   :dependencies [[org.clojure/clojure "1.6.0"]])

REPL (loop read-eval-print) é uma ferramenta para experimentar o código Clojure. Ele permite que você interaja com um programa em execução e teste rapidamente se as coisas funcionam como deveriam. Ele faz isso apresentando um prompt onde você pode inserir o código. Ele então lê sua entrada, avalia, imprime o resultado e faz um loop, apresentando a você um prompt novamente.

Este processo permite um ciclo de feedback rápido que não é possível na maioria dos outros idiomas.

Iniciando uma Sessão REPL

Uma sessão REPL pode ser iniciada em Leiningen digitando o seguinte comando na linha de comando.

lein repl

Isso iniciará a seguinte janela REPL.

Em seguida, você começa a avaliar os comandos do Clojure na janela REPL conforme necessário.

Para iniciar uma sessão REPL no Eclipse, clique na opção Menu, vá para Executar como → Aplicativo Clojure.

Isso iniciará uma nova sessão REPL em uma janela separada junto com a saída do console.

Conceitualmente, REPL é semelhante ao Secure Shell (SSH). Da mesma forma que você pode usar o SSH para interagir com um servidor remoto, o Clojure REPL permite que você interaja com um processo Clojure em execução. Este recurso pode ser muito poderoso porque você pode até anexar um REPL a um aplicativo de produção ao vivo e modificar seu programa enquanto ele é executado.

Variáveis ​​especiais em REPL

REPL inclui algumas variáveis ​​úteis, a amplamente utilizada é a variável especial * 1, * 2 e * 3. Eles são usados ​​para avaliar os resultados das três expressões mais recentes.

O exemplo a seguir mostra como essas variáveis ​​podem ser usadas.

user => "Hello"
Hello
user => "World"
World
user => (str *2 *1)
HelloWorld

No exemplo acima, as duas primeiras strings estão sendo enviadas para a janela de saída REPL como “Hello” e “World” respectivamente. Em seguida, as variáveis ​​* 2 e * 1 são usadas para recuperar as 2 últimas expressões avaliadas.

Clojure oferece uma grande variedade de built-in data types.

Tipos de dados integrados

A seguir está uma lista de tipos de dados que são definidos no Clojure.

  • Integers - A seguir estão as representações dos inteiros disponíveis no Clojure.

    • Decimal Integers (Short, Long and Int)- São usados ​​para representar números inteiros. Por exemplo, 1234.

    • Octal Numbers- São usados ​​para representar números na representação octal. Por exemplo, 012.

    • Hexadecimal Numbers- São usados ​​para representar números na representação. Por exemplo, 0xff.

    • Radix Numbers- São usados ​​para representar números na representação da raiz. Por exemplo, 2r1111 em que a raiz é um número inteiro entre 2 e 36, inclusive.

  • Floating point

    • O padrão é usado para representar números de ponto flutuante de 32 bits. Por exemplo, 12,34.

    • A outra representação é a notação científica. Por exemplo, 1.35e-12.

  • char- Isso define um único literal de caractere. Os caracteres são definidos com o símbolo de folga. Por exemplo, / e.

  • Boolean - Isso representa um valor booleano, que pode ser verdadeiro ou falso.

  • String- Estes são literais de texto que são representados na forma de uma cadeia de caracteres. Por exemplo, “Hello World”.

  • Nil - Isso é usado para representar um valor NULL em Clojure.

  • Atom- Os átomos fornecem uma maneira de gerenciar o estado independente, síncrono e compartilhado. Eles são um tipo de referência como refs e vars.

Valores Vinculados

Como todos os tipos de dados em Clojure são herdados de Java, os valores limitados são os mesmos da linguagem de programação Java. A tabela a seguir mostra os valores máximos permitidos para os literais numéricos e decimais.

literais Gamas
Baixo -32.768 a 32.767
int -2.147.483.648 a 2.147.483.647
grandes -9.223.372.036.854.775.808 a +9.223.372.036.854.775.807
flutuador 1.40129846432481707e-45 a 3.40282346638528860e + 38
em dobro 4.94065645841246544e-324d a 1.79769313486231570e + 308d

Tipos numéricos de classe

Além dos tipos primitivos, os seguintes tipos de objeto (às vezes chamados de tipos de invólucro) são permitidos.

Nome
java.lang.Byte
java.lang.Short
java.lang.Integer
java.lang.Long
java.lang.Float
java.lang.Double

Exemplo

O programa a seguir mostra um código de Clojure consolidado para demonstrar os tipos de dados em Clojure.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   ;; The below code declares a integer variable
   (def x 1)
   
   ;; The below code declares a float variable
   (def y 1.25)
   
   ;; The below code declares a string variable
   (def str1 "Hello")
   (println x)
   (println y)
   (println str1))
(Example)

Resultado

O programa acima produz a seguinte saída.

1
1.25
Hello

Em Clojure, variables são definidos pelo ‘def’palavra-chave. É um pouco diferente em que o conceito de variáveis ​​tem mais a ver com vinculação. Em Clojure, um valor está vinculado a uma variável. Uma coisa importante a se notar no Clojure é que as variáveis ​​são imutáveis, o que significa que, para que o valor da variável mude, ela precisa ser destruída e recriada novamente.

A seguir estão os tipos básicos de variáveis ​​no Clojure.

  • short- Isso é usado para representar um número curto. Por exemplo, 10.

  • int- Isso é usado para representar números inteiros. Por exemplo, 1234.

  • long- Isso é usado para representar um número longo. Por exemplo, 10000090.

  • float- Isso é usado para representar números de ponto flutuante de 32 bits. Por exemplo, 12,34.

  • char- Isso define um único literal de caractere. Por exemplo, '/ a'.

  • Boolean - Isso representa um valor booleano, que pode ser verdadeiro ou falso.

  • String- Estes são literais de texto que são representados na forma de uma cadeia de caracteres. Por exemplo, “Hello World”.

Declarações de variáveis

A seguir está a sintaxe geral para definir uma variável.

Sintaxe

(def var-name var-value)

Onde 'var-name' é o nome da variável e 'var-value' é o valor associado à variável.

Exemplo

A seguir está um exemplo de declaração de variável.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   ;; The below code declares a integer variable
   (def x 1)
   
   ;; The below code declares a float variable
   (def y 1.25)

   ;; The below code declares a string variable
   (def str1 "Hello")
   
   ;; The below code declares a boolean variable
   (def status true))
(Example)

Nomeando Variáveis

O nome de uma variável pode ser composto de letras, dígitos e o caractere de sublinhado. Deve começar com uma letra ou um sublinhado. Letras maiúsculas e minúsculas são distintas porque Clojure, assim como Java, é uma linguagem de programação que diferencia maiúsculas de minúsculas.

Exemplo

A seguir estão alguns exemplos de nomenclatura de variáveis ​​em Clojure.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   ;; The below code declares a Boolean variable with the name of status
   (def status true)
   
   ;; The below code declares a Boolean variable with the name of STATUS
   (def STATUS false)
   
   ;; The below code declares a variable with an underscore character.
   (def _num1 2))
(Example)

Note - Nas declarações acima, devido à distinção entre maiúsculas e minúsculas, status e STATUS são duas variáveis ​​diferentes definidas em Clojure.

O exemplo acima mostra como definir uma variável com um caractere de sublinhado.

Variáveis ​​de impressão

Visto que Clojure usa o ambiente JVM, você também pode usar a função 'println'. O exemplo a seguir mostra como isso pode ser alcançado.

Exemplo

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   ;; The below code declares a integer variable
   (def x 1)
   
   ;; The below code declares a float variable
   (def y 1.25)
   
   ;; The below code declares a string variable
   (def str1 "Hello")
   (println x)
   (println y)
   (println str1))
(Example)

Resultado

O programa acima produz a seguinte saída.

1
1.25
Hello

A operator é um símbolo que diz ao compilador para realizar manipulações matemáticas ou lógicas específicas.

Clojure tem os seguintes tipos de operadores -

  • Operadores aritméticos
  • Operadores relacionais
  • Operadores lógicos
  • Operadores bit a bit

Note - No Clojure, os operadores e operandos funcionam da seguinte maneira de sintaxe.

Sintaxe

(operator operand1 operand2 operandn)

Por exemplo,

Exemplo

(+ 1 2)

O exemplo acima faz uma operação aritmética nos números 1 e 2.

Operadores aritméticos

A linguagem Clojure suporta os operadores aritméticos normais como qualquer linguagem. A seguir estão os operadores aritméticos disponíveis no Clojure.

Mostrar exemplos

Operador Descrição Exemplo
+ Adição de dois operandos (+ 1 2) dará 3
- Subtrai o segundo operando do primeiro (- 2 1) dará 1
* Multiplicação de ambos os operandos (* 2 2) dará 4
/ Divisão do numerador por denominador (flutuante (/ 3 2)) dará 1,5
inc Operadores incrementais usados ​​para incrementar o valor de um operando em 1 inc 5 dará 6
dezembro Operadores incrementais usados ​​para diminuir o valor de um operando em 1 5 de dezembro dará 4
max Retorna o maior de seus argumentos no máximo 1 2 3 retornará 3
min Retorna o menor de seus argumentos min 1 2 3 retornará 1
rem Restante da divisão do primeiro número pelo segundo rem 3 2 dará 1

Operadores Relacionais

Os operadores relacionais permitem a comparação de objetos. A seguir estão os operadores relacionais disponíveis em Clojure.

Mostrar exemplos

Operador Descrição Exemplo
= Testa a igualdade entre dois objetos (= 2 2) dará verdadeiro
não = Testa a diferença entre dois objetos (não = 3 2) dará verdadeiro
< Verifica se o objeto esquerdo é menor que o operando direito (<2 3) dará verdadeiro
<= Verifica se o objeto esquerdo é menor ou igual ao operando direito (<= 2 3) dará verdadeiro
> Verifica se o objeto esquerdo é maior que o operando direito (> 3 2) dará verdadeiro
> = Verifica se o objeto esquerdo é maior ou igual ao operando direito (> = 3 2) dará verdadeiro

Operadores lógicos

Operadores lógicos são usados ​​para avaliar expressões booleanas. A seguir estão os operadores lógicos disponíveis no Groovy.

Mostrar exemplos

Operador Descrição Exemplo
and Este é o operador lógico “e” (ou verdadeiro verdadeiro) dará verdadeiro
or Este é o operador lógico “ou” (e verdadeiro falso) dará falso
not Este é o operador lógico “não” (não falso) dará verdadeiro

O fragmento de código a seguir mostra como os vários operadores podem ser usados.

Operadores bit a bit

Clojure fornece quatro operadores bit a bit. A seguir estão os operadores bit a bit disponíveis no Clojure.

Mostrar exemplos

Sr. Não. Operador e descrição
1

bit-and

Este é o operador bit a bit “e”

2

bit-or

Este é o operador bit a bit “ou”

3

bit-xor

Este é o bit a bit “xor” ou operador exclusivo 'ou'

4

bit-not

Este é o operador de negação bit a bit

A seguir está a tabela verdade mostrando esses operadores.

p q p & q p | q p ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

operador precedente

Como é o caso com LISPs em geral, não há necessidade de se preocupar com a precedência do operador. Este é um dos benefícios das expressões S e da notação de prefixo. Todas as funções são avaliadas da esquerda para a direita e de dentro para fora. Os operadores em Clojure são apenas funções e tudo está entre parênteses.

Até agora, vimos instruções que são executadas uma após a outra de maneira sequencial. Além disso, as instruções são fornecidas no Clojure para alterar o fluxo de controle na lógica de um programa. Eles são então classificados em declarações de fluxo de controle que veremos em detalhes.

Sr. Não. Loops e descrição
1 Declaração While

o 'while' A instrução é executada avaliando primeiro a expressão da condição (um valor booleano) e, se o resultado for verdadeiro, as instruções no loop while são executadas.

2 Declaração Doseq

o ‘doseq’declaração é semelhante à declaração 'para cada' que é encontrada em muitas outras linguagens de programação. A instrução doseq é basicamente usada para iterar em uma sequência.

3 Declaração Dotimes

o ‘dotimes’ instrução é usada para executar uma instrução 'x' número de vezes.

4 Declaração de Loop

A forma especial de loop não é como um ‘for’ciclo. O uso de loop é o mesmo que a ligação let. No entanto, o loop define um ponto de recursão

Decision-making structures exigem que o programador especifique uma ou mais condições a serem avaliadas ou testadas pelo programa, juntamente com uma instrução ou instruções a serem executadas se a condição for determinada como verdadeira e, opcionalmente, outras instruções a serem executadas se a condição for determinada como seja falso.

Sr. Não. Métodos e Descrição
1 Declaração If

Em Clojure, a condição é uma expressão que a avalia como verdadeira ou falsa. 'If' a condição for verdadeira, então a instrução nº 1 será executada, caso contrário, a instrução nº 2 será executada.

2 Se / faço Expressão

o ‘if-do’ expressão em Clojure é usada para permitir que várias expressões sejam executadas para cada ramificação da instrução 'if'.

3 Declaração aninhada If

Múltiplo 'if' declarações embutidas umas nas outras.

4 Declaração do Caso

Clojure oferece o ‘case’ declaração que é semelhante ao ‘switch’ declaração disponível na linguagem de programação Java.

5 Declaração Cond

Clojure oferece outra declaração de avaliação chamada de ‘cond’declaração. Esta instrução leva um conjunto de pares de teste / expressão.

Clojure é conhecido como uma linguagem de programação funcional, portanto, você esperaria ver muita ênfase em como as funções funcionam no Clojure. Este capítulo cobre o que tudo pode ser feito com funções no Clojure.

Sr. Não. Funções e descrição
1 Definindo uma função

Uma função é definida usando o ‘defn’ macro.

2 Funções anônimas

Uma função anônima é uma função que não possui um nome associado a ela.

3 Funções com vários argumentos

As funções Clojure podem ser definidas com zero ou mais parâmetros. Os valores que você passa para as funções são chamadosarguments, e os argumentos podem ser de qualquer tipo.

4 Funções Variadicas

Clojure oferece a instrução 'case' que é semelhante à instrução 'switch' disponível na linguagem de programação Java.

5 Funções de ordem superior

Funções de ordem superior (HOFs) são funções que usam outras funções como argumentos. HOFs são uma técnica de programação funcional importante e são muito comumente usados ​​em Clojure.

Numbers o tipo de dados em Clojure é derivado de classes Java.

Clojure suporta números inteiros e de ponto flutuante.

  • Um número inteiro é um valor que não inclui uma fração.

  • Um número de ponto flutuante é um valor decimal que inclui uma fração decimal.

A seguir está um exemplo de números em Clojure.

(def x 5)
(def y 5.25)

Onde 'x' é do tipo Integer e 'y' é o float.

Em Java, as seguintes classes são anexadas aos números definidos em Clojure.

Para realmente ver que os números em Clojure são derivados de classes Java, use o seguinte programa para ver o tipo de números atribuídos ao usar o comando 'def'.

Exemplo

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (def x 5)
   (def y 5.25)
   (println (type x))
   (println (type y)))
(Example)

o ‘type’ comando é usado para produzir a classe associada ao valor atribuído a uma variável.

Resultado

O código acima produzirá a seguinte saída.

Java.lang.long
Java.lang.double

Testes numéricos

As funções de teste a seguir estão disponíveis para números.

Sr. Não. Números e descrição
1 zero?

Retorna verdadeiro se o número for zero, senão falso.

2 pos?

Retorna verdadeiro se o número for maior que zero, senão falso.

3 neg?

Retorna verdadeiro se o número for menor que zero, senão falso.

4 até?

Retorna verdadeiro se o número for par e lança uma exceção se o número não for um inteiro.

5 ímpar?

Retorna verdadeiro se o número for ímpar e lança uma exceção se o número não for um inteiro.

6 número?

Retorna verdadeiro se o número for realmente um Número.

7 inteiro?

Retorna verdadeiro se o número for um inteiro.

8 flutuador?

Retorna verdadeiro se o número for um float.

Vimos a instrução recorrente em um tópico anterior e, enquanto o loop 'for' é um pouco como um loop, recur é um loop real em Clojure.

Se você tem experiência em programação, talvez já tenha ouvido falar da recursão da cauda, ​​que é um dos principais recursos das linguagens funcionais. Esta forma especial recorrente é aquela que implementa a recursão da cauda. Como a palavra “recursão da cauda” indica, recur deve ser chamado na posição da cauda. Em outras palavras, a recorrência deve ser a última coisa a ser avaliada.

O exemplo mais simples da instrução recorrente é usado dentro do loop 'for'. No exemplo a seguir, a instrução recur é usada para alterar o valor da variável 'i' e alimentar o valor da variável de volta para a expressão de loop.

Exemplo

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (loop [i 0]
      (when (< i 5)
      (println i)
      (recur (inc i)))))
(Example)

Resultado

O programa acima produz a seguinte saída.

0
1
2
3
4

Clojure fornece vários métodos auxiliares ao trabalhar com E / S. Ele oferece classes mais fáceis para fornecer as seguintes funcionalidades para arquivos.

  • Lendo arquivos
  • Gravando em arquivos
  • Ver se um arquivo é um arquivo ou diretório

Vamos explorar algumas das operações de arquivo que Clojure tem a oferecer.

Lendo o conteúdo de um arquivo como uma string inteira

Se você deseja obter todo o conteúdo do arquivo como uma string, você pode usar o clojure.core.slurpmétodo. O comando slurp abre um leitor em um arquivo e lê todo o seu conteúdo, retornando uma string.

A seguir está um exemplo de como isso pode ser feito.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (def string1 (slurp "Example.txt"))
   (println string1))
(Example)

Se o arquivo contiver as seguintes linhas, elas serão impressas como -

line : Example1
line : Example2

Ler o conteúdo de um arquivo uma linha de cada vez

Se você deseja obter todo o conteúdo do arquivo como uma string, uma linha de cada vez, você pode usar o clojure.java.io/readermétodo. A classe clojure.java.io/reader cria um buffer de leitura, que é usado para ler cada linha do arquivo.

A seguir está um exemplo que mostra como isso pode ser feito.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (with-open [rdr (clojure.java.io/reader "Example.txt")]
   (reduce conj [] (line-seq rdr))))
(Example)

If the file contains the following lines, they will be printed as −

line : Example1
line : Example2

The output will be shown as −

["line : Example1" "line : Example2"]

Writing ‘to’ Files

If you want to write ‘to’ files, you can use the clojure.core.spit command to spew entire strings into files. The spit command is the opposite of the slurp method. This method opens a file as a writer, writes content, then closes file.

Following is an example.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (spit "Example.txt"
      "This is a string"))

In the above example, if you see the contents of the Example.txt file , you will see the contents of “This is a string”.

Writing ‘to’ Files One Line at a Time

If you want to write ‘to’ files one line at a time, you can use the clojure.java.io.writer class. The clojure.java.io.writer class is used to create a writer stream wherein bytes of data are fed into the stream and subsequently into the file.

Following is an example that shows how the spit command can be used.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (with-open [w (clojure.java.io/writer "Example.txt" :append true)]
      (.write w (str "hello" "world"))))
(Example)

When the above code is executed, the line “hello world” will be present in the Example.txt file. The append:true option is to append data to the file. If this option is not specified, then the file will be overwritten whenever data is written to the file.

Checking to See If a File Exists

To check if a file exists, the clojure.java.io.file class can be used to check for the existence of a file. Following is an example that shows how this can be accomplished.

(ns clojure.examples.hello
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (println (.exists (clojure.java.io/file "Example.txt"))))
(Example)

If the file Example.txt exists, the output will be true.

Reading from the Console

To read data from the console, the read-line statement can be used. Following is an example that shows how this can be used.

If you enter the (read-line) command in the REPL window, you will have the chance to enter some input in the console window.

user->(read-line)
Hello World

The above code will produce the following output.

“Hello World”

A String literal is constructed in Clojure by enclosing the string text in quotations. Strings in Clojure need to be constructed using the double quotation marks such as “Hello World”.

Example

Following is an example of the usage of strings in Clojure.

(ns clojure.examples.hello
   (:gen-class))
(defn hello-world []
   (println "Hello World")
   (println "This is a demo application"))
(hello-world)

Output

The above program produces the following output.

Hello World
This is a demo application

Basic String Operations

Clojure has a number of operations that can be performed on strings. Following are the operations.

Sr.No. String Operations & Description
1 str

The concatenation of strings can be done by the simple str function.

2 format

The formatting of strings can be done by the simple format function. The format function formats a string using java.lang.String.format.

3 count

Returns the number of characters in the string.

4 subs

Returns the substring of ‘s’ beginning at start inclusive, and ending at end (defaults to length of string), exclusive.

5 compare

Returns a negative number, zero, or a positive number when ‘x’ is logically 'less than', 'equal to', or 'greater than' ‘y’.

6 lower-case

Converts string to all lower-case.

7 upper-case

Converts string to all upper-case.

8 join

Returns a string of all elements in collection, as returned by (seq collection), separated by an optional separator.

9 split

Splits string on a regular expression.

10 split-lines

Split strings is based on the escape characters \n or \r\n.

11 reverse

Reverses the characters in a string.

12 replace

Replaces all instance of a match in a string with the replacement string.

13 trim

Removes whitespace from both ends of the string.

14 triml

Removes whitespace from the left hand side of the string.

15 trimr

Removes whitespace from the right hand side of the string.

List is a structure used to store a collection of data items. In Clojure, the List implements the ISeq interface. Lists are created in Clojure by using the list function.

Example

Following is an example of creating a list of numbers in Clojure.

(ns clojure.examples.example
   (:gen-class))
(defn example []
   (println (list 1 2 3 4)))
(example)

Output

The above code produces the following output.

(1 2 3 4)

Following is an example of creating a list of characters in Clojure.

(ns clojure.examples.example
   (:gen-class))
(defn example []
   (println (list 'a 'b 'c 'd)))
(example)

The above code produces the following output.

(a b c d)

Following are the list methods available in Clojure.

Sr.No. Lists & Description
1 list*

Creates a new list containing the items prepended to the rest, the last of which will be treated as a sequence.

2 first

This function returns the first item in the list.

3 nth

This function returns the item in the ‘nth’ position in the list.

4 cons

Returns a new list wherein an element is added to the beginning of the list.

5 conj

Returns a new list wherein the list is at the beginning and the elements to be appended are placed at the end.

6 rest

Returns the remaining items in the list after the first item.

Sets in Clojure are a set of unique values. Sets are created in Clojure with the help of the set command.

Example

Following is an example of the creation of sets in Clojure.

(ns clojure.examples.example
   (:gen-class))
(defn example []
   (println (set '(1 1 2 2))))
(example)

Output

The above code produces the following output.

#{1,2}

Following are the methods available in Clojure for sets.

Sr.No. Sets & Description
1 sorted-set

Returns a sorted set of elements.

2 get

Returns the element at the index position.

3 contains?

Finds out whether the set contains a certain element or not.

4 conj

Appends an element to the set and returns the new set of elements.

5 disj

Disjoins an element from the set.

6 union

Return a set that is the union of the input sets

7 difference

Return a set that is the first set without elements of the remaining sets.

8 intersection

Return a set that is the intersection of the input sets.

9 subset?

Is set1 a subset of set2?

10 superset?

Is set1 a superset of set2?

A Vector is a collection of values indexed by contiguous integers. A vector is created by using the vector method in Clojure.

Example

Following is an example of creating a vector in Clojure.

(ns clojure.examples.example
   (:require [clojure.set :as set])
   (:gen-class))
(defn example []
   (println (vector 1 2 3)))
(example)

Output

The above code produces the following output.

[1 2 3]

Following are the methods available in Clojure.

Sr.No. Vectors & Description
1 vector-of

Creates a new vector of a single primitive type ‘t’, where ‘t’ is one of :int :long :float :double :byte :short :char or :boolean.

2 nth

This function returns the item in the nth position in the vector.

3 get

Returns the element at the index position in the vector.

4 conj

Appends an element to the vector and returns the new set of vector elements.

5 pop

For a list or queue, returns a new list/queue without the first item, for a vector, returns a new vector without the last item.

6 subvec

Returns a sub vector from a starting and ending index.

A Map is a collection that maps keys to values. Two different map types are provided - hashed and sorted. HashMaps require keys that correctly support hashCode and equals. SortedMaps require keys that implement Comparable, or an instance of Comparator.

A map can be created in two ways, the first is via the hash-map method.

Creation - HashMaps

HashMaps have a typical key value relationship and is created by using hash-map function.

(ns clojure.examples.example
   (:gen-class))
(defn example []
   (def demokeys (hash-map "z" "1" "b" "2" "a" "3"))
   (println demokeys))
(example)

Output

The above code produces the following output.

{z 1, b 2, a 3}

Creation - SortedMaps

SortedMaps have the unique characteristic of sorting their elements based on the key element. Following is an example that shows how the sorted map can be created using the sorted-map function.

(ns clojure.examples.example
   (:gen-class))
(defn example []
   (def demokeys (sorted-map "z" "1" "b" "2" "a" "3"))
   (println demokeys))
(example)

The above code produces the following output.

{a 3, b 2, z 1}

From the above program you can clearly see that elements in the maps are sorted as per the key value. Following are the methods available for maps.

Sr.No. Maps & Description
1 get

Returns the value mapped to key, not-found or nil if key is not present.

2 contains?

See whether the map contains a required key.

3 find

Returns the map entry for the key.

4 keys

Returns the list of keys in the map.

5 vals

Returns the list of values in the map.

6 dissoc

Dissociates a key value entry from the map.

7 merge

Merges two maps entries into one single map entry.

8 merge-with

Returns a map that consists of the rest of the maps conj-ed onto the first.

9 select-keys

Returns a map containing only those entries in map whose key is in keys.

10 rename-keys

Renames keys in the current HashMap to the newly defined ones.

11 map-invert

Inverts the maps so that the values become the keys and vice versa.

Namespaces in Clojure are used to differentiate classes into separate logical spaces just like in Java. Consider the following statement.

(:require [clojure.set :as set])

In the above statement, ‘clojure.set’ is a namespace which contains various classes and methods to be used in the program. For example, the above namespace contains the function called map-invert, which is used to invert a map of key-values. We cannot use this function unless we explicitly tell our program to include this namespace.

Let’s look at the different methods available for namespaces.

Sr.No. Methods & Description
1 *ns*

This is used to look at your current namespace.

2 ns

This is used to create a new namespace and associate it with the running program.

3 alias

Add an alias in the current namespace to another namespace. Arguments are two symbols: the alias to be used and the symbolic name of the target namespace.

4 all-ns

Returns a list of all namespaces.

5 find-ns

Finds and returns a particular namespace.

6 ns-name

Returns the name of a particular namespace.

7 ns-aliases

Returns the aliases, which are associated with any namespaces.

8 ns-map

Returns a map of all the mappings for the namespace.

9 un-alias

Returns a map containing only those entries in map whose key is in keys.

Exception handling is required in any programming language to handle the runtime errors so that the normal flow of the application can be maintained. Exception usually disrupts the normal flow of the application, which is the reason why we need to use exception handling in our application.

Exception is broadly classified into the following categories −

  • Checked Exception − The classes that extend Throwable class except RuntimeException and Error are known as checked exceptions. E.g. IOException, SQLException, etc. Checked exceptions are checked at compile-time.

Let’s consider the following program which does an operation on a file called Example.txt. However, there can be always a case wherein the file Example.txt does not exist.

(ns clojure.examples.example
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (def string1 (slurp "Example.txt"))
   (println string1))
(Example)

If the file Example.txt does not exist, then the following exception will be generated by the program.

Caused by: java.io.FileNotFoundException: Example.txt (No such file or
directory)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at clojure.java.io$fn__9185.invoke(io.clj:229) at clojure.java.io$fn__9098$G__9091__9105.invoke(io.clj:69) at clojure.java.io$fn__9197.invoke(io.clj:258)
at clojure.java.io$fn__9098$G__9091__9105.invoke(io.clj:69)

A partir da exceção acima, podemos ver claramente que o programa gerou uma FileNotFoundException.

  • Unchecked Exception- As classes que estendem RuntimeException são conhecidas como exceções não verificadas. Por exemplo, ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException, etc. As exceções não verificadas não são verificadas em tempo de compilação, em vez disso, são verificadas em tempo de execução.

Um caso clássico é a ArrayIndexOutOfBoundsException que acontece quando você tenta acessar um índice de uma matriz que é maior que o comprimento da matriz. A seguir está um exemplo típico desse tipo de erro.

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (try
      (aget (int-array [1 2 3]) 5)
      (catch Exception e (println (str "caught exception: " (.toString e))))
      (finally (println "This is our final block")))
   (println "Let's move on"))
(Example)

Quando o código acima é executado, a seguinte exceção será levantada.

caught exception: java.lang.ArrayIndexOutOfBoundsException: 5
This is our final block
Let's move on

Erro

O erro é irrecuperável, por exemplo, OutOfMemoryError, VirtualMachineError, AssertionError, etc. Esses são erros dos quais o programa nunca pode se recuperar e que farão com que o programa trave. Agora precisamos de algum mecanismo para capturar essas exceções para que o programa possa continuar a ser executado se essas exceções existirem.

O diagrama a seguir mostra como a hierarquia de exceções em Clojure é organizada. Tudo é baseado na hierarquia definida em Java.

Captura de exceções

Assim como outras linguagens de programação, Clojure fornece o bloco normal 'try-catch' para capturar exceções como e quando elas ocorrem.

A seguir está a sintaxe geral do bloco try-catch.

(try
   (//Protected code)
   catch Exception e1)
(//Catch block)

Todo o seu código que poderia gerar uma exceção é colocado no Protected code block.

No catch block, você pode escrever um código personalizado para manipular sua exceção para que o aplicativo possa se recuperar da exceção.

Vejamos nosso exemplo anterior que gerou uma exceção de arquivo não encontrado e ver como podemos usar o bloco try catch para capturar a exceção levantada pelo programa.

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (try
      (def string1 (slurp "Example.txt"))
      (println string1)
      (catch Exception e (println (str "caught exception: " (.getMessage e))))))
(Example)

O programa acima produz a seguinte saída.

caught exception: Example.txt (No such file or directory)

A partir do código acima, resolvemos o código defeituoso no try block. No bloco catch, estamos apenas capturando nossa exceção e enviando uma mensagem de que ocorreu uma exceção. Portanto, agora temos uma maneira significativa de capturar a exceção, que é gerada pelo programa.

Vários blocos de captura

Pode-se ter vários blocos catch para lidar com vários tipos de exceções. Para cada bloco catch, dependendo do tipo de exceção levantada, você escreveria o código para tratá-la de acordo.

Vamos modificar nosso código anterior para incluir dois blocos catch, um que é específico para nossa exceção de arquivo não encontrado e o outro é para um bloco de exceção geral.

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (try
      (def string1 (slurp "Example.txt"))
      (println string1)
      
      (catch java.io.FileNotFoundException e (println (str "caught file
         exception: " (.getMessage e))))
      
      (catch Exception e (println (str "caught exception: " (.getMessage e)))))
   (println "Let's move on"))
(Example)

O programa acima produz a seguinte saída.

caught file exception: Example.txt (No such file or directory)
Let's move on

A partir da saída acima, podemos ver claramente que nossa exceção foi capturada pelo bloco de captura 'FileNotFoundException' e não pelo geral.

Finalmente Bloco

O bloco finalmente segue um bloco try ou um bloco catch. Um bloco final de código sempre é executado, independentemente da ocorrência de uma Exceção.

Usar um bloco finally permite que você execute quaisquer instruções do tipo de limpeza que deseja executar, não importa o que aconteça no código protegido. A seguir está a sintaxe para este bloco.

(try
   (//Protected code)
   catch Exception e1)
(//Catch block)
(finally
   //Cleanup code)

Vamos modificar o código acima e adicionar o bloco finally de código. A seguir está o trecho de código.

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (try
      (def string1 (slurp "Example.txt"))
      (println string1)
      
      (catch java.io.FileNotFoundException e (println (str "caught file
         exception: " (.getMessage e))))
      
      (catch Exception e (println (str "caught exception: " (.getMessage e))))
      (finally (println "This is our final block")))
   (println "Let's move on"))
(Example)

O programa acima produz a seguinte saída.

caught file exception: Example.txt (No such file or directory)
This is our final block
Let's move on

No programa acima, você pode ver que o bloco final também é implementado depois que o bloco catch captura a exceção necessária.

Como Clojure deriva seu tratamento de exceções de Java, semelhante a Java, os seguintes métodos estão disponíveis em Clojure para gerenciar as exceções.

  • public String getMessage()- Retorna uma mensagem detalhada sobre a exceção que ocorreu. Esta mensagem é inicializada no construtor Throwable.

  • public Throwable getCause() - Retorna a causa da exceção conforme representado por um objeto Throwable.

  • public String toString() - Retorna o nome da classe concatenada com o resultado de getMessage ().

  • public void printStackTrace() - Imprime o resultado de toString () junto com o rastreamento de pilha em System.err, o fluxo de saída de erro.

  • public StackTraceElement [] getStackTrace()- Retorna uma matriz contendo cada elemento no rastreamento de pilha. O elemento no índice 0 representa o topo da pilha de chamadas e o último elemento na matriz representa o método na parte inferior da pilha.

  • public Throwable fillInStackTrace() - Preenche o rastreamento da pilha deste objeto Throwable com o rastreamento da pilha atual, adicionando a qualquer informação anterior no rastreamento da pilha.

A seguir está o código de exemplo que usa alguns dos métodos listados acima.

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (try
      (def string1 (slurp "Example.txt"))
      (println string1)
      
      (catch java.io.FileNotFoundException e (println (str "caught file
         exception: " (.toString e))))
      
      (catch Exception e (println (str "caught exception: " (.toString e))))
   (finally (println "This is our final block")))
   (println "Let's move on"))
(Example)

O programa acima produz a seguinte saída.

caught file exception: java.io.FileNotFoundException: Example.txt (No such file
or directory)
This is our final block
Let's move on

Sequences são criados com a ajuda do ‘seq’comando. A seguir está um exemplo simples de uma criação de sequência.

(ns clojure.examples.example
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (println (seq [1 2 3])))
(Example)

O programa acima produz a seguinte saída.

(1 2 3)

A seguir estão os vários métodos disponíveis para sequências.

Sr. Não. Métodos e Descrição
1 contras

Retorna uma nova sequência onde 'x' é o primeiro elemento e 'seq' é o resto.

2 conj

Retorna uma nova sequência em que 'x' é o elemento adicionado ao final da sequência.

3 concat

Isso é usado para concatear duas sequências.

4 distinto

Usado apenas para garantir que elementos distintos sejam adicionados à sequência.

5 reverter

Inverte os elementos na sequência.

6 primeiro

Retorna o primeiro elemento da sequência.

7 último

Retorna o último elemento da sequência.

8 descansar

Retorna toda a sequência, exceto o primeiro elemento.

9 ordenar

Retorna uma sequência classificada de elementos.

10 solta

Descarta elementos de uma sequência com base no número de elementos que precisam ser removidos.

11 levar por último

Obtém a última lista de elementos da sequência.

12 levar

Obtém a primeira lista de elementos da sequência.

13 dividir em

Divide a sequência de itens em duas partes. Um local é especificado no qual a divisão deve acontecer.

UMA regular expressioné um padrão usado para localizar substrings no texto. Expressões regulares são usadas em uma variedade de linguagens de programação e muito usadas em linguagens de programação do tipo LISP.

A seguir está um exemplo de uma expressão regular.

//d+

A expressão regular acima é usada para encontrar mais uma ocorrência de um dígito em uma string. Os caracteres // são usados ​​para garantir que os caracteres 'd' e '+' sejam usados ​​para representar uma expressão regular.

Em geral, as expressões regulares funcionam com o seguinte conjunto de regras.

  • Existem dois caracteres posicionais especiais usados ​​para denotar o início e o fim de uma linha: circunflexo (∧) e cifrão ($):

  • As expressões regulares também podem incluir quantificadores. O sinal de mais (+) representa uma ou mais vezes, aplicado ao elemento anterior da expressão. O asterisco (*) é usado para representar zero ou mais ocorrências. O ponto de interrogação (?) Denota zero ou uma vez.

  • O metacaractere {e} é usado para corresponder a um número específico de instâncias do caractere anterior.

  • Em uma expressão regular, o símbolo de ponto (.) Pode representar qualquer caractere. Isso é descrito como o caractere curinga.

  • Uma expressão regular pode incluir classes de caracteres. Um conjunto de caracteres pode ser dado como uma sequência simples de caracteres entre os metacaracteres [e] como em [aeiou]. Para intervalos de letras ou números, você pode usar um separador de traço como em [a – z] ou [a – mA – M]. O complemento de uma classe de caracteres é denotado por um acento circunflexo à esquerda entre colchetes como em [∧a – z] e representa todos os caracteres além dos especificados.

Os métodos a seguir estão disponíveis para expressões regulares.

Sr. Não. Métodos e Descrição
1 re-padrão

Retorna uma instância de java.util.regex.Pattern. Isso é então usado em outros métodos para correspondência de padrões.

2 reencontrar

Retorna a próxima correspondência de regex, se houver, da string para o padrão, usando java.util.regex.Matcher.find ()

3 substituir

A função de substituição é usada para substituir uma substring em uma string por um novo valor de string. A busca pela substring é feita com o uso de um pattern.

4 substitua primeiro

A função de substituição é usada para substituir uma substring em uma string por um novo valor de string, mas apenas para a primeira ocorrência da substring. A busca pela substring é feita com o uso de um pattern.

Predicatessão funções que avaliam uma condição e fornecem um valor verdadeiro ou falso. Vimos funções de predicado nos exemplos do capítulo sobre números. Vimos funções como 'mesmo?' que é usado para testar se um número é par ou não, ou 'neg?' que é usado para testar se um número é maior que zero ou não. Todas essas funções retornam um valor verdadeiro ou falso.

A seguir está um exemplo de predicados em Clojure.

(ns clojure.examples.example
   (:gen-class))

;; This program displays Hello World
(defn Example []
   (def x (even? 0))
   (println x)
   
   (def x (neg? 2))
   (println x)
   
   (def x (odd? 3))
   (println x)
   
   (def x (pos? 3))
   (println x))
(Example)

O programa acima produz a seguinte saída.

true
false
true
true

Além das funções de predicado normais, Clojure fornece mais funções para predicados. Os métodos a seguir estão disponíveis para predicados.

Sr. Não. Métodos e Descrição
1 todo predador

Pega um conjunto de predicados e retorna uma função 'f' que retorna verdadeiro se todos os seus predicados de composição retornam um valor lógico verdadeiro contra todos os seus argumentos, caso contrário, retorna falso.

2 cada?

Retorna verdadeiro se o predicado for verdadeiro para todos os valores, senão falso.

3 alguns

Retorna o primeiro valor verdadeiro lógico para qualquer valor de predicado de x na coleção de valores.

4 nenhum?

Retorna falso se qualquer um dos predicados dos valores em uma coleção for logicamente verdadeiro, caso contrário, verdadeiro.

Destructuring é uma funcionalidade do Clojure, que permite extrair valores de uma estrutura de dados, como um vetor, e vinculá-los a símbolos sem ter que atravessar explicitamente a estrutura de dados.

Vejamos um exemplo do que exatamente significa desestruturação e como isso acontece.

Exemplo

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (def my-vector [1 2 3 4])
   (let [[a b c d] my-vector]
   (println a b c d)))
(Example)

O programa acima produz a seguinte saída.

Resultado

1 2 3 4

No exemplo acima, as seguintes coisas devem ser observadas -

  • Estamos definindo um vetor de inteiros como 1, 2, 3 e 4.

  • Estamos então usando o ‘let’ para atribuir 4 variáveis ​​(a, b, c e d) à variável my-vetor diretamente.

  • Se executarmos o ‘println’ declaração sobre as quatro variáveis, podemos ver que eles já foram atribuídos aos valores no vetor, respectivamente.

Portanto, o clojure desestruturou a variável my-vector, que tinha quatro valores quando foi atribuída usando a instrução 'let'. Os quatro valores desconstruídos foram então atribuídos aos quatro parâmetros em conformidade.

Se houver variáveis ​​em excesso que não tenham um valor correspondente ao qual possam ser atribuídas, elas receberão o valor nulo. O exemplo a seguir esclarece esse ponto.

Exemplo

(ns clojure.examples.hello
   (:gen-class))
(defn Example []
   (def my-vector [1 2 3 4])
   (let [[a b c d e] my-vector]
   (println a b c d e)))
(Example)

O programa acima produz a seguinte saída. Você pode ver na saída que, como a última variável 'e' não tem um valor correspondente no vetor, ela é nula.

Resultado

1 2 3 4 nil

o resto

A variável 'the-rest' é usada para armazenar os valores restantes, que não podem ser atribuídos a nenhuma variável.

Um exemplo de como isso é usado é mostrado no programa a seguir.

Exemplo

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (def my-vector [1 2 3 4])
   (let [[a b & the-rest] my-vector]
   (println a b the-rest)))
(Example)

O programa acima produz a seguinte saída. Na saída, você pode ver claramente que os valores de 3 e 4 não podem ser atribuídos a nenhuma variável, portanto, eles são atribuídos à variável 'o resto'.

Resultado

1 2 (3 4)

Mapas de Destruição

Assim como os vetores, os mapas também podem ser desestruturados. A seguir está um exemplo de como isso pode ser feito.

Exemplo

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (def my-map {"a" 1 "b" 2})
   (let [{a "a" b "b"} my-map]
   (println a b)))
(Example)

O programa acima produz a seguinte saída. No programa, você pode ver claramente que os valores do mapa de “a” e “b” são atribuídos às variáveis ​​de a e b.

Resultado

1 2

Da mesma forma, no caso de vetores, se não houver um valor correspondente no mapa quando a desestruturação ocorrer, então a variável receberá um valor nulo.

A seguir está um exemplo.

Exemplo

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (def my-map {"a" 1 "b" 2})
   (let [{a "a" b "b" c "c"} my-map]
   (println a b c)))
(Example)

O programa acima produz a seguinte saída.

Resultado

1 2 nil

Como a estrutura Clojure é derivada de classes Java, pode-se usar as classes de data e hora disponíveis em Java no Clojure. oclass date representa um instante específico no tempo, com precisão de milissegundos.

A seguir estão os métodos disponíveis para a classe de data e hora.

java.util.Date

Isso é usado para criar o objeto de data em Clojure.

Sintaxe

A seguir está a sintaxe.

java.util.Date.

Parameters - Nenhum.

Return Value - Aloca um objeto Date e o inicializa de forma que represente a hora em que foi alocado, medido no milissegundo mais próximo.

Exemplo

Um exemplo de como isso é usado é mostrado no programa a seguir.

(ns example)
(defn Example []
   (def date (.toString (java.util.Date.)))
   (println date))
(Example)

Resultado

O programa acima produz a seguinte saída. Isso dependerá da data e hora atuais no sistema, no qual o programa está sendo executado.

Tue Mar 01 06:11:17 UTC 2016

java.text.SimpleDateFormat

Isso é usado para formatar a saída de data.

Sintaxe

A seguir está a sintaxe.

(java.text.SimpleDateFormat. format dt)

Parameters- 'formato' é o formato a ser usado ao formatar a data. 'dt' é a data que deve ser formatada.

Return Value - Uma saída de data formatada.

Exemplo

Um exemplo de como isso é usado é mostrado no programa a seguir.

(ns example)
(defn Example []
   (def date (.format (java.text.SimpleDateFormat. "MM/dd/yyyy") (new java.util.Date)))
   (println date))
(Example)

Resultado

O programa acima produz a seguinte saída. Isso dependerá da data e hora atuais no sistema, no qual o programa está sendo executado.

03/01/2016

consiga tempo

Retorna o número de milissegundos desde 1º de janeiro de 1970, 00:00:00 GMT representado por este objeto Date.

Sintaxe

A seguir está a sintaxe.

(.getTime)

Parameters - Nenhum.

Return Value - O número de milissegundos desde 1º de janeiro de 1970, 00:00:00 GMT representado por esta data.

Exemplo

Um exemplo de como isso é usado é mostrado no programa a seguir.

(ns example)
(import java.util.Date)
(defn Example []
   (def date (.getTime (java.util.Date.)))
   (println date))
(Example)

Resultado

O programa acima produz a seguinte saída. Isso dependerá da data e hora atuais no sistema, no qual o programa está sendo executado.

1456812778160

Atomssão um tipo de dados no Clojure que fornecem uma maneira de gerenciar o estado independente, síncrono e compartilhado. Um átomo é como qualquer tipo de referência em qualquer outra linguagem de programação. O principal uso de um átomo é manter as estruturas de dados imutáveis ​​de Clojure. O valor mantido por um átomo é alterado com oswap! method.

Internamente, troque! lê o valor atual, aplica a função a ele e tenta compará-lo e configurá-lo. Como outro thread pode ter alterado o valor no intervalo de tempo, pode ser necessário tentar novamente e o faz em um loop de rotação. O efeito líquido é que o valor sempre será o resultado da aplicação da função fornecida a um valor atual, atomicamente.

Exemplo

Os átomos são criados com a ajuda do método do átomo. Um exemplo do mesmo é mostrado no programa a seguir.

(ns clojure.examples.example
   (:gen-class))
(defn example []
   (def myatom (atom 1))
   (println @myatom))
(example)

Resultado

O programa acima produz o seguinte resultado.

1

O valor de átomo é acessado usando o símbolo @. Clojure possui algumas operações que podem ser realizadas em átomos. A seguir estão as operações.

Sr. Não. Operações e descrição
1 Redefinir!

Define o valor do átomo para um novo valor sem levar em consideração o valor atual.

2 comparar e definir!

Atomicamente define o valor do átomo para o novo valor se e somente se o valor atual do átomo for idêntico ao valor antigo mantido pelo átomo. Retorna verdadeiro se set acontecer, senão retorna falso.

3 troca!

Atomicamente troca o valor do átomo por um novo com base em uma função específica.

Em Clojure, metadataé usado para anotar os dados em uma coleção ou para os dados armazenados em um símbolo. Isso normalmente é usado para anotar dados sobre tipos para o compilador subjacente, mas também pode ser usado para desenvolvedores. Metadados não são considerados parte do valor do objeto. Ao mesmo tempo, os metadados são imutáveis.

As seguintes operações são possíveis em Clojure com relação aos metadados.

Sr. Não. Operações e descrição
1 meta-com

Esta função é usada para definir um mapa de metadados para qualquer objeto.

2 meta

Esta função é usada para ver se algum metadado está associado a um objeto.

3 variar-meta

Retorna um objeto do mesmo tipo e valor do objeto original, mas com metadados combinados.

StructMapssão usados ​​para criar estruturas em Clojure. Por exemplo, se você deseja criar uma estrutura composta por um nome de funcionário e um ID de funcionário, pode fazer isso com StructMaps.

As seguintes operações são possíveis em Clojure com relação a StructMaps.

Sr. Não. Operações e descrição
1 defstruir

Esta função é usada para definir a estrutura necessária.

2 estrutura

Esta função é usada para definir um objeto de estrutura do tipo, que é criado pela operação defstruct.

3 struct-map

Esta função é usada para atribuir valores especificamente a valores de chave, definindo explicitamente quais valores são atribuídos a quais chaves na estrutura.

4 Acessando Campos Individuais

Campos individuais da estrutura podem ser acessados ​​acessando as chaves junto com o objeto de estrutura.

5 Natureza Imutável

Por padrão, as estruturas também são imutáveis, portanto, se tentarmos alterar o valor de uma chave específica, ele não mudará.

6 Adicionando uma Nova Chave à Estrutura

Como as estruturas são imutáveis, a única maneira de adicionar outra chave à estrutura é por meio da criação de uma nova estrutura. Um exemplo de como isso pode ser alcançado é mostrado no programa a seguir.

Como apontado muitas vezes, Clojure é uma linguagem de programação em que muitos dos tipos de dados são imutáveis, o que significa que a única maneira de alterar o valor de uma variável é criar uma nova variável e atribuir o novo valor a ela. No entanto, Clojure fornece alguns elementos, que podem criar um estado mutável. Vimos que isso pode ser alcançado com o tipo de dados atom. A outra maneira de fazer isso é por meio de agentes.

Agentsfornecer mudança independente e assíncrona de locais individuais. Os agentes são vinculados a um único local de armazenamento por toda a vida e permitem que a mutação desse local (para um novo estado) ocorra apenas como resultado de uma ação. Ações são funções (com, opcionalmente, argumentos adicionais) que são aplicadas de forma assíncrona ao estado de um Agente e cujo valor de retorno se torna o novo estado do Agente.

As seguintes operações são possíveis em Clojure com relação a Agentes.

Sr. Não. Operações e descrição
1 agente

Um agente é criado usando o comando do agente.

2 enviar

Esta função é usada para enviar um valor ao agente.

3 agentes de desligamento

Esta função é usada para encerrar qualquer agente em execução.

4 despedida

Existem casos em que um agente é atribuído a uma função que é de natureza de bloqueio.

5 aguardar

Como há um atraso quando um valor de um agente é atualizado, Clojure forneceu uma função 'esperar por' que é usada para especificar o tempo em milissegundos para esperar pela atualização do agente.

6 aguardam

Bloqueia o encadeamento atual (indefinidamente!) Até que todas as ações despachadas até agora, deste encadeamento ou agente, para o (s) agente (s) tenham ocorrido. Bloqueará em agentes com falha.

7 erro de agente

Retorna a exceção lançada durante uma ação assíncrona do agente, se o agente falhar. Retorna nulo se o agente não falhar.

Watcherssão funções adicionadas a tipos de variáveis, como átomos e variáveis ​​de referência, que são chamadas quando um valor do tipo de variável muda. Por exemplo, se o programa de chamada alterar o valor de uma variável atom e se uma função de observador for anexada à variável atom, a função será chamada assim que o valor do átomo for alterado.

As funções a seguir estão disponíveis no Clojure for Watchers.

adicionar relógio

Adiciona uma função de observação a uma referência de agente / átomo / var / ref. O relógio‘fn’deve ser um 'fn' de 4 args: uma chave, a referência, seu estado antigo, seu estado novo. Sempre que o estado da referência pode ter sido alterado, quaisquer relógios registrados terão suas funções chamadas.

Sintaxe

A seguir está a sintaxe.

(add-watch variable :watcher
   (fn [key variable-type old-state new-state]))

Parameters- 'variável' é o nome do átomo ou variável de referência. 'tipo de variável' é o tipo de variável, seja átomo ou variável de referência. 'old-state & new-state' são parâmetros que manterão automaticamente o valor antigo e o novo da variável. 'key' deve ser única por referência e pode ser usada para remover o relógio com remove-watch.

Return Value - Nenhum.

Exemplo

Um exemplo de como isso é usado é mostrado no programa a seguir.

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (def x (atom 0))
   (add-watch x :watcher
      (fn [key atom old-state new-state]
      (println "The value of the atom has been changed")
      (println "old-state" old-state)
      (println "new-state" new-state)))
(reset! x 2))
(Example)

Resultado

O programa acima produz a seguinte saída.

The value of the atom has been changed
old-state 0
new-state 2

remover-assistir

Remove um relógio que foi anexado a uma variável de referência.

Sintaxe

A seguir está a sintaxe.

(remove-watch variable watchname)

Parameters- 'variável' é o nome do átomo ou variável de referência. 'watchname' é o nome dado ao relógio quando a função de relógio é definida.

Return Value - Nenhum.

Exemplo

Um exemplo de como isso é usado é mostrado no programa a seguir.

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (def x (atom 0))
   (add-watch x :watcher
      (fn [key atom old-state new-state]
         (println "The value of the atom has been changed")
         (println "old-state" old-state)
         (println "new-state" new-state)))
   (reset! x 2)
   (remove-watch x :watcher)
(reset! x 4))
(Example)

Resultado

O programa acima produz a seguinte saída.

The value of the atom has been changed
old-state 0
new-state 2

Você pode ver claramente no programa acima que o segundo comando de reinicialização não aciona o observador, pois foi removido da lista do observador.

Em qualquer idioma, Macrossão usados ​​para gerar código embutido. Clojure não é exceção e fornece recursos de macro simples para desenvolvedores. As macros são usadas para escrever rotinas de geração de código, que fornecem ao desenvolvedor uma maneira poderosa de adaptar a linguagem às necessidades do desenvolvedor.

A seguir estão os métodos disponíveis para macros.

defmacro

Esta função é usada para definir sua macro. A macro terá um nome de macro, uma lista de parâmetros e o corpo da macro.

Sintaxe

A seguir está a sintaxe.

(defmacro name [params*] body)

Parameters- 'nome' é o nome da macro. 'params' são os parâmetros atribuídos à macro. 'corpo' é o corpo da macro.

Return Value - Nenhum.

Exemplo

Um exemplo de como isso é usado é mostrado no programa a seguir.

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (defmacro Simple []
      (println "Hello"))
   (macroexpand '(Simple)))
(Example)

Resultado

O programa acima produz a seguinte saída.

Hello

No programa acima, você pode ver que a macro 'Simples' é expandida em linha para 'println' “Olá”. Macros são semelhantes a funções, com a única diferença de que os argumentos para um formulário são avaliados no caso de macros.

macro-expansão

Isso é usado para expandir uma macro e colocar o código embutido no programa.

Sintaxe

A seguir está a sintaxe.

(macroexpand macroname)

Parameters - 'macroname' é o nome da macro que precisa ser expandida.

Return Value - A macro expandida.

Exemplo

Um exemplo de como isso é usado é mostrado no programa a seguir.

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (defmacro Simple []
      (println "Hello"))
   (macroexpand '(Simple)))
(Example)

Resultado

O programa acima produz a seguinte saída.

Hello

Macro com Argumentos

As macros também podem ser usadas para aceitar argumentos. A macro pode receber qualquer número de argumentos. O exemplo a seguir mostra como os argumentos podem ser usados.

Exemplo

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (defmacro Simple [arg]
      (list 2 arg))
   (println (macroexpand '(Simple 2))))
(Example)

O exemplo acima coloca um argumento na macro Simples e então usa o argumento para adicionar o valor do argumento a uma lista.

Resultado

O programa acima produz a seguinte saída.

(2 2)

Reference valuessão outra maneira de o Clojure trabalhar com a demanda de variáveis ​​mutáveis. Clojure fornece tipos de dados mutáveis, como átomos, agentes e tipos de referência.

A seguir estão as operações disponíveis para valores de referência.

Sr. Não. Operações e descrição
1 ref

Isso é usado para criar um valor de referência. Ao criar um valor de referência, existe a opção de fornecer uma função de validador, que irá validar o valor criado.

2 ref-set

Esta função é usada para definir o valor de uma referência para um novo valor, independentemente de qualquer que seja o valor mais antigo.

3 alterar

Esta função é usada para alterar o valor de um tipo de referência, mas de maneira segura. Isso é executado em um thread, que não pode ser acessado por outro processo.

4 dosync

Executa a expressão (em um do implícito) em uma transação que abrange a expressão e todas as chamadas aninhadas.

5 comutar

Commute também é usado para alterar o valor de um tipo de referência, assim como alter e ref-set.

Para usar a funcionalidade de banco de dados, certifique-se de primeiro fazer o download do jdbc files do seguinte url - https://codeload.github.com/clojure/java.jdbc/zip/master

Você encontrará um arquivo zip que contém os drivers necessários para que o Clojure possa se conectar a bancos de dados. Depois que o arquivo zip for extraído, certifique-se de adicionar o local descompactado ao seu classpath.

O arquivo principal para conectividade de banco de dados é um arquivo chamado jdbc.clj no local clojure / java.

O conector clojure jdbc oferece suporte a uma ampla variedade de bancos de dados, alguns dos quais são os seguintes.

  • H2Database
  • Oracle
  • Microsoft SQL Server
  • MySQL
  • PostgreSQL

Em nosso exemplo, usaremos o banco de dados MySQL como exemplo.

As seguintes operações são possíveis no Clojure com relação aos bancos de dados.

Conexão de banco de dados

Antes de se conectar a um banco de dados MySQL, certifique-se do seguinte:

  • Você criou um banco de dados TESTDB.

  • Você criou uma tabela EMPLOYEE em TESTDB.

  • Esta tabela contém os campos FIRST_NAME, LAST_NAME, AGE, SEX e INCOME.

  • O ID do usuário "testuser" e a senha "test123" são definidos para acessar o TESTDB.

  • Certifique-se de ter baixado o 'arquivo jar mysql' e adicionado o arquivo ao seu classpath.

  • Você passou pelo tutorial do MySQL para entender os fundamentos do MySQL .

Sintaxe

A seguir está a sintaxe para criar uma conexão no Clojure.

(def connection_name {
   :subprotocol “protocol_name”
   :subname “Location of mysql DB”
   :user “username” :password “password” })

Parameters- 'connection_name' é o nome a ser dado à conexão. 'subprotocol' é o protocolo a ser usado para a conexão. Por padrão, usaremos o protocolo mysql. 'subnome' é o url para conectar ao banco de dados mysql junto com o nome do banco de dados. 'usuário' é o nome de usuário usado para se conectar ao banco de dados. 'senha' é a senha a ser usada para conectar ao banco de dados.

Return Value - Isso fornecerá uma string de conexão, que pode ser usada em operações subsequentes do mysql.

O exemplo a seguir mostra como se conectar às tabelas no esquema de informações e recuperar todos os dados da tabela.

Exemplo

(ns test.core
   (:require [clojure.java.jdbc :as sql]))
(defn -main []
   (def mysql-db {
      :subprotocol "mysql"
      :subname "//127.0.0.1:3306/information_schema"
      :user "root"
      :password "shakinstev"})
   (println (sql/query mysql-db
      ["select table_name from tables"]
      :row-fn :table_name)))

Consultando dados

Consultar dados em qualquer banco de dados significa buscar algumas informações úteis do banco de dados. Depois que uma conexão de banco de dados for estabelecida, você estará pronto para fazer uma consulta a esse banco de dados. A seguir está a sintaxe pela qual os dados podem ser consultados usando Clojure.

Sintaxe

clojure.java.jdbc/query dbconn
["query"]
   :row-fn :sequence

Parameters- 'dbconn' é o nome da conexão usada para conectar ao banco de dados. 'query' é a string de consulta usada para buscar dados do banco de dados. ': sequência' é, por padrão, todas as linhas de dados buscadas no banco de dados e é retornado como uma sequência. As operações necessárias na sequência podem então ser feitas para ver quais dados foram buscados.

Return Value - Isso retornará uma sequência, que terá as linhas de dados da operação de consulta.

O exemplo a seguir mostra como se conectar à tabela de funcionários e buscar a coluna first_name das linhas da tabela.

Exemplo

(ns test.core
   (:require [clojure.java.jdbc :as sql]))
(defn -main []
   (def mysql-db {
      :subprotocol "mysql"
      :subname "//127.0.0.1:3306/testdb"
      :user "root"
      :password "shakinstev"})
   (println (sql/query mysql-db
      ["select first_name from employee"]
      :row-fn :first_name)))

Pelo código acima, podemos ver que

  • A consulta de “selecionar o nome do funcionário” é passada como string de consulta.

  • O: first_name é a sequência, que é retornada como resultado da operação de busca.

Se assumirmos que existe apenas uma linha em nosso banco de dados que contém um valor first_name de John, a seguir será a saída do programa acima.

(John)

Inserindo Dados

É necessário quando você deseja criar seus registros em uma tabela de banco de dados. A seguir está a sintaxe pela qual os dados podem ser inseridos usando Clojure. Isso é feito usando o‘insert!’ função.

Sintaxe

clojure.java.jdbc/insert!
   :table_name {:column_namen columnvalue}

Parameters- ': table_name' é o nome da tabela em que a inserção deve ser feita. '{: column_namen columnvalue}' é um mapa de todos os nomes e valores de coluna, que precisam ser adicionados como uma linha na tabela.

Return Value - Isso retornará nulo se a inserção for feita com sucesso.

O exemplo a seguir mostra como inserir um registro na tabela de funcionários no banco de dados testdb.

Exemplo

(ns test.core
   (:require [clojure.java.jdbc :as sql]))
(defn -main []
   (def mysql-db {
      :subprotocol "mysql"
      :subname "//127.0.0.1:3306/testdb"
      :user "root"
      :password "shakinstev"})
   (sql/insert! mysql-db
      :employee {:first_name "John" :last_name "Mark" :sex "M" :age 30 :income 30}))

Se você verificar agora seu banco de dados MySQL e a tabela de funcionários, verá que a linha acima será inserida com êxito na tabela.

Excluindo Dados

As linhas podem ser excluídas de uma tabela usando o ‘delete!’função. A seguir está a sintaxe de como essa operação pode ser executada.

Sintaxe

clojure.java.jdbc/delete!
   :table_name [condition]

Parameters- ': table_name' é o nome da tabela em que a inserção deve ser feita. 'condição' é a condição usada para determinar qual linha precisa ser excluída da tabela.

Return Value - Isso retornará o número de linhas excluídas.

O exemplo a seguir mostra como excluir um registro da tabela de funcionários no banco de dados testdb. O exemplo exclui uma linha da tabela com base na condição de que a idade seja igual a 30.

Exemplo

(ns test.core
   (:require [clojure.java.jdbc :as sql]))
(defn -main []
   (def mysql-db {
      :subprotocol "mysql"
      :subname "//127.0.0.1:3306/testdb"
      :user "root"
      :password "shakinstev"})
   (println (sql/delete! mysql-db
      :employee ["age = ? " 30])))

Se você tinha um registro com uma linha com idade igual ao valor 30, essa linha será excluída.

Atualizando Dados

As linhas podem ser atualizadas de uma tabela usando o ‘update!’função. A seguir está a sintaxe de como essa operação pode ser executada.

Sintaxe

clojure.java.jdbc/update!
   :table_name
{setcondition}
[condition]

Parameters- ': table_name' é o nome da tabela em que a inserção deve ser feita. 'setcondition' é a coluna que precisa ser atualizada conforme mencionado em termos de um mapa. 'condição' é a condição que é usada para determinar qual linha precisa ser excluída da tabela.

Return Value - Isso retornará o número de linhas atualizadas.

O exemplo a seguir mostra como excluir um registro da tabela de funcionários no banco de dados testdb. O exemplo atualiza uma linha da tabela com base na condição de que a idade seja igual a 30 e atualiza o valor da renda para 40.

(ns test.core
   (:require [clojure.java.jdbc :as sql]))
(defn -main []
   (def mysql-db {
      :subprotocol "mysql"
      :subname "//127.0.0.1:3306/testdb"
      :user "root"
      :password "shakinstev"})
   (println (sql/update! mysql-db
      :employee
      {:income 40}
      ["age = ? " 30])))

Se você tivesse um registro com uma linha com idade igual ao valor 30, essa linha será atualizada e o valor da renda será definido para 40.

Transações

As transações são mecanismos que garantem a consistência dos dados. As transações têm as seguintes quatro propriedades -

  • Atomicity - Ou uma transação é concluída ou nada acontece.

  • Consistency - Uma transação deve começar em um estado consistente e deixar o sistema em um estado consistente.

  • Isolation - Os resultados intermediários de uma transação não são visíveis fora da transação atual.

  • Durability - Depois que uma transação foi confirmada, os efeitos são persistentes, mesmo após uma falha do sistema.

Exemplo

O exemplo a seguir mostra como implementar transações em Clojure. Todas as operações que precisam ser realizadas em uma transação precisam ser incorporadas no‘with-dbtransaction’ cláusula.

(ns test.core
   (:require [clojure.java.jdbc :as sql]))
(defn -main []
   (def mysql-db {
      :subprotocol "mysql"
      :subname "//127.0.0.1:3306/testdb"
      :user "root"
      :password "shakinstev"})
   (sql/with-db-transaction [t-con mysql-db]
      (sql/update! t-con
         :employee
         {:income 40}
         ["age = ? " 30])))

Como já sabemos, o código Clojure é executado no ambiente virtual Java no final. Portanto, só faz sentido que Clojure seja capaz de utilizar todas as funcionalidades do Java. Neste capítulo, vamos discutir a correlação entre Clojure e Java.

Chamando Métodos Java

Os métodos Java podem ser chamados usando a notação de ponto. Um exemplo são strings. Uma vez que todas as strings em Clojure são strings Java, você pode chamar métodos Java normais em strings.

Um exemplo de como isso é feito é mostrado no programa a seguir.

Exemplo

(ns Project
   (:gen-class))
(defn Example []
   (println (.toUpperCase "Hello World")))
(Example)

O programa acima produz a seguinte saída. Você pode ver no código que, se apenas chamar a notação de ponto para qualquer método de string, ela também funcionará no Clojure.

Resultado

HELLO WORLD

Chamando métodos Java com parâmetros

Você também pode chamar métodos Java com parâmetros. Um exemplo de como isso é feito é mostrado no programa a seguir.

Exemplo

(ns Project
   (:gen-class))
(defn Example []
   (println (.indexOf "Hello World","e")))
(Example)

O programa acima produz a seguinte saída. Você pode ver pelo código acima, que estamos passando o parâmetro “e” para o método indexOf. O programa acima produz a seguinte saída.

Resultado

1

Criação de objetos Java

Os objetos podem ser criados em Clojure usando a palavra-chave 'novo' semelhante ao que é feito em Java.

Um exemplo de como isso é feito é mostrado no programa a seguir.

Exemplo

(ns Project
   (:gen-class))
(defn Example []
   (def str1 (new String "Hello"))
   (println str1))
(Example)

O programa acima produz a seguinte saída. Você pode ver no código acima, que podemos usar a palavra-chave 'new' para criar um novo objeto da classe String existente do Java. Podemos passar o valor ao criar o objeto, assim como fazemos em Java. O programa acima produz a seguinte saída.

Resultado

Hello

A seguir está outro exemplo que mostra como podemos criar um objeto da classe Integer e usá-lo nos comandos normais do Clojure.

Exemplo

(ns Project
   (:gen-class))
(defn Example []
   (def my-int(new Integer 1))
   (println (+ 2 my-int)))
(Example)

O programa acima produz a seguinte saída.

Resultado

3

Comando de Importação

Também podemos usar o comando import para incluir bibliotecas Java no namespace para que as classes e métodos possam ser acessados ​​facilmente.

O exemplo a seguir mostra como podemos usar o comando import. No exemplo, estamos usando o comando import para importar as classes dojava.util.stackbiblioteca. Podemos então usar o método push e pop da classe stack como eles são.

Exemplo

(ns Project
   (:gen-class))
(import java.util.Stack)
(defn Example []
   (let [stack (Stack.)]
   (.push stack "First Element")
   (.push stack "Second Element")
   (println (first stack))))
(Example)

O programa acima produz a seguinte saída.

Resultado

First Element

Executando código usando o comando Java

O código Clojure pode ser executado usando o comando Java. A seguir está a sintaxe de como isso pode ser feito.

java -jar clojure-1.2.0.jar -i main.clj

Você deve mencionar o arquivo jar do Clojure, para que todas as classes baseadas em Clojure sejam carregadas no JVM. O arquivo 'main.clj' é o arquivo de código Clojure que precisa ser executado.

Funções Java integradas

Clojure pode usar muitas das funções integradas do Java. Alguns deles são -

Math PI function- Clojure pode usar o método Math para o valor de PI. A seguir está um código de exemplo.

Exemplo

(ns Project
   (:gen-class))
(defn Example []
   (println (. Math PI)))
(Example)

O código acima produz a seguinte saída.

Resultado

3.141592653589793

System Properties- Clojure também pode consultar as propriedades do sistema. A seguir está um código de exemplo.

Exemplo

(ns Project
   (:gen-class))
(defn Example []
   (println (.. System getProperties (get "java.version"))))
(Example)

Dependendo da versão do Java no sistema, o valor correspondente será exibido. A seguir está um exemplo de saída.

Resultado

1.8.0_45

Na programação Clojure, a maioria dos tipos de dados são imutáveis, portanto, quando se trata de programação simultânea, o código que usa esses tipos de dados é bastante seguro quando o código é executado em vários processadores. Porém, muitas vezes, há um requisito para compartilhar dados e, quando se trata de dados compartilhados entre vários processadores, é necessário garantir que o estado dos dados seja mantido em termos de integridade ao trabalhar com vários processadores. Isso é conhecido comoconcurrent programming e Clojure fornece suporte para essa programação.

O sistema de memória transacional de software (STM), exposto por meio de dosync, ref, set, alter, etc. suporta o compartilhamento de estado de mudança entre threads de maneira síncrona e coordenada. O sistema do agente suporta o compartilhamento de mudança de estado entre threads de maneira assíncrona e independente. O sistema de átomos suporta o compartilhamento de estado de mudança entre threads de maneira síncrona e independente. Considerando que o sistema var dinâmico, exposto por meio de def, binding, etc. suporta o isolamento de estado de mudança dentro das threads.

Outras linguagens de programação também seguem o modelo de programação simultânea.

  • Eles têm uma referência direta aos dados que podem ser alterados.

  • Se o acesso compartilhado for necessário, o objeto será bloqueado, o valor será alterado e o processo continuará para o próximo acesso a esse valor.

Em Clojure não há bloqueios, mas referências indiretas a estruturas de dados persistentes imutáveis.

Existem três tipos de referências em Clojure.

  • Vars - As mudanças são isoladas em threads.

  • Refs - As mudanças são sincronizadas e coordenadas entre os threads.

  • Agents - Envolve mudanças independentes assíncronas entre threads.

As seguintes operações são possíveis no Clojure com relação à programação simultânea.

Transações

A simultaneidade em Clojure é baseada em transações. As referências só podem ser alteradas dentro de uma transação. As seguintes regras são aplicadas nas transações.

  • Todas as mudanças são atômicas e isoladas.
  • Cada mudança em uma referência acontece em uma transação.
  • Nenhuma transação vê o efeito feito por outra transação.
  • Todas as transações são colocadas dentro do bloco dosync.

Já vimos o que o bloco dosync faz, vamos examiná-lo novamente.

dosync

Executa a expressão (em um do implícito) em uma transação que abrange a expressão e todas as chamadas aninhadas. Inicia uma transação se nenhuma já estiver em execução neste encadeamento. Qualquer exceção não detectada abortará a transação e sairá do dosync.

A seguir está a sintaxe.

Sintaxe

(dosync expression)

Parameters - 'expressão' é o conjunto de expressões que virão no bloco dosync.

Return Value - Nenhum.

Vejamos um exemplo em que tentamos alterar o valor de uma variável de referência.

Exemplo

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (def names (ref []))
   (alter names conj "Mark"))
(Example)

Resultado

O programa acima, quando executado, apresenta o seguinte erro.

Caused by: java.lang.IllegalStateException: No transaction running
   at clojure.lang.LockingTransaction.getEx(LockingTransaction.java:208)
   at clojure.lang.Ref.alter(Ref.java:173)
   at clojure.core$alter.doInvoke(core.clj:1866)
   at clojure.lang.RestFn.invoke(RestFn.java:443)
   at clojure.examples.example$Example.invoke(main.clj:5) at clojure.examples.example$eval8.invoke(main.clj:7)
   at clojure.lang.Compiler.eval(Compiler.java:5424)
   ... 12 more

Com o erro, você pode ver claramente que não pode alterar o valor de um tipo de referência sem primeiro iniciar uma transação.

Para que o código acima funcione, temos que colocar o comando alter em um bloco dosync como feito no programa a seguir.

Exemplo

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (def names (ref []))
   
   (defn change [newname]
      (dosync
         (alter names conj newname)))
   (change "John")
   (change "Mark")
   (println @names))
(Example)

O programa acima produz a seguinte saída.

Resultado

[John Mark]

Vamos ver outro exemplo de dosync.

Exemplo

(ns clojure.examples.example
   (:gen-class))
(defn Example []
   (def var1 (ref 10))
   (def var2 (ref 20))
   (println @var1 @var2)
   
   (defn change-value [var1 var2 newvalue]
      (dosync
         (alter var1 - newvalue)
         (alter var2 + newvalue)))
   (change-value var1 var2 20)
   (println @var1 @var2))
(Example)

No exemplo acima, temos dois valores que estão sendo alterados em um bloco dosync. Se a transação for bem-sucedida, ambos os valores serão alterados, caso contrário, toda a transação falhará.

O programa acima produz a seguinte saída.

Resultado

10 20
-10 40

Clojure tem algumas bibliotecas contribuídas que têm a capacidade de criar Desktop e Web-based applications. Vamos discutir cada um deles.

Sr. Não. Aplicativos e descrição
1 Desktop - gangorra

O See-saw é uma biblioteca que pode ser usada para criar aplicativos de desktop.

2 Desktop - Mudando o valor do texto

O valor do conteúdo na janela pode ser alterado usando o ‘config!’opção. No exemplo a seguir, o config! opção é usada para alterar o conteúdo da janela para o novo valor de “Good Bye”.

3 Desktop - Exibindo uma caixa de diálogo modal

Uma caixa de diálogo modal pode ser exibida usando o método de alerta da classe gangorra. O método assume o valor do texto, que precisa ser mostrado na caixa de diálogo modal.

4 Desktop - Exibindo botões

Os botões podem ser exibidos com a ajuda da classe de botões.

5 Desktop - Exibindo rótulos

Os rótulos podem ser exibidos com a ajuda da classe de rótulos.

6 Desktop - Exibindo Campos de Texto

Os campos de texto podem ser exibidos com a ajuda da classe de texto.

Aplicativos da Web - Introdução

Para criar um aplicativo da web em Clojure você precisa usar a biblioteca de aplicativos do Ring, que está disponível no seguinte link https://github.com/ring-clojure/ring

Você precisa certificar-se de baixar os jars necessários do site e adicioná-los como uma dependência para o aplicativo Clojure.

o Ring framework fornece os seguintes recursos -

  • Configura as coisas de forma que uma solicitação http entre em seu aplicativo da web como um Clojure HashMap regular e, da mesma forma, faz com que você possa retornar uma resposta como um HashMap.

  • Fornece uma especificação que descreve exatamente como esses mapas de solicitação e resposta devem ser.

  • Traz um servidor web (Jetty) e conecta seu aplicativo web a ele.

O framework Ring pode iniciar automaticamente um servidor web e garante que o aplicativo Clojure funcione neste servidor. Então também se pode usar a estrutura Compojure. Isso permite criar rotas que agora são a forma como a maioria dos aplicativos da web modernos são desenvolvidos.

Creating your first Clojure application - O exemplo a seguir mostra como você pode criar seu primeiro aplicativo da web no Clojure.

(ns my-webapp.handler
   (:require [compojure.core :refer :all]
      [compojure.route :as route]
      [ring.middleware.defaults :refer [wrap-defaults site-defaults]]))
(defroutes app-routes
   (GET "/" [] "Hello World")
   (route/not-found "Not Found"))
(def app
   (wrap-defaults app-routes site-defaults))

Vejamos os seguintes aspectos do programa -

  • o ‘defroutes’ é usado para criar rotas de forma que a solicitação feita ao aplicativo da web para diferentes rotas possa ser direcionada para diferentes funções em seu aplicativo Clojure.

  • No exemplo acima, o “/” é conhecido como a rota padrão, portanto, quando você navegar até a base do seu aplicativo da web, a string “Hello World” será enviada ao navegador da web.

  • Se o usuário acessar qualquer url que não possa ser processada pelo aplicativo Clojure, ele exibirá a string “Não encontrado”.

Ao executar o aplicativo Clojure, por padrão, seu aplicativo será carregado como localhost: 3000, portanto, se você navegar até este local, receberá a seguinte saída.

Aplicativos da Web - Adicionando mais rotas ao seu aplicativo da Web

Você também pode adicionar mais rotas ao seu aplicativo da web. O exemplo a seguir mostra como fazer isso.

(ns my-webapp.handler
   (:require [compojure.core :refer :all]
      [compojure.route :as route]
      [ring.middleware.defaults :refer [wrap-defaults site-defaults]]))
(defroutes app-routes
   (GET "/" [] "Hello World")
   (GET "/Tutorial" [] "This is a tutorial on Clojure")
   (route/not-found "Not Found"))
(def app
   (wrap-defaults app-routes site-defaults))

Você pode ver que adicionar uma rota no aplicativo é tão fácil quanto adicionar outra função GET com a rota de url. (GET "/ Tutorial" [] "Este é um tutorial sobre Clojure")

Se você navegar até o local http://localhost:3000/Tutorial, você receberá a seguinte saída.

Neste capítulo, vamos discutir as opções de teste automatizado fornecidas pelo Clojure.

Teste de aplicativos cliente

Para usar o teste para o framework Clojure, você deve usar as dependências localizadas em https://github.com/slagyr/speclj#manual-installation

Este URL fornece o specljframework, que é usado como um framework de teste baseado em dados de teste ou baseado em comportamento para Clojure. Você deve garantir o uso da estrutura Clojure 1.7.0 ao usar qualquer uma das bibliotecas 'speclj'. Por padrão, os arquivos de teste serão diferentes dos arquivos de código do Clojure e precisam ser colocados em um diretório 'spec'.

A seguir está um código de amostra para um arquivo de teste.

(ns change.core-spec
   (:require [speclj.core :refer :all]))
(describe "Truth"
   (it "is true"
   (should true))
   (it "is not false"
   (should-not false)))
(run-specs)

O seguinte deve ser observado sobre o código acima -

  • Primeiro, temos que garantir o uso da instrução 'require' para incluir todas as bibliotecas centrais na estrutura 'speclj'.

  • A seguir está a função 'descrever'. Isso é usado para fornecer uma descrição para o caso de teste que está sendo criado.

  • A próxima função é a função 'it', que é o caso de teste real. No primeiro caso de teste, a string “é verdadeiro” é o nome dado ao caso de teste.

  • Devem e não devem são conhecidos como assertions. Todas as afirmações começam com deveria. Deveria e não deveria são apenas duas das muitas afirmações disponíveis. Ambos assumem expressões que verificarão quanto à veracidade e falsidade, respectivamente.

Se você executar o caso de teste, obterá a seguinte saída. A saída mostra o tempo gasto em milissegundos para a execução do caso de teste.

←[32m.←[0m←[32m.←[0m
Finished in 0.00014 seconds

Teste de aplicativos baseados na web

Seleniumé uma das principais estruturas usadas para testar aplicativos modernos baseados na web. Bibliotecas Clojure também estão disponíveis, as quais podem ser usadas para testar aplicativos baseados na web.

Vejamos como podemos usar as bibliotecas Selenium para testar aplicativos Clojure baseados na web.

Step 1- A primeira etapa é garantir que estamos usando a estrutura Ring e Compojure para criar um aplicativo baseado na web, que precisa ser testado. Vamos usar um dos exemplos de nossos capítulos anteriores. O código a seguir é um aplicativo da web simples, que exibe “Hello World” no navegador.

(ns my-webapp.handler
   (:require [compojure.core :refer :all]
      [compojure.route :as route]
      [ring.middleware.defaults :refer [wrap-defaults site-defaults]]))
(defroutes app-routes
   (GET "/" [] "Hello World")
   (route/not-found "Not Found"))
(def app
   (wrap-defaults app-routes site-defaults))

Step 2 - Em seguida, certifique-se de baixar o arquivo jar de selênio https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-server/2.47.0 e inclua-o em seu classpath.

Step 3 - Certifique-se também de baixar o driver da web 'clj', que será usado para executar o teste da web no seguinte local.

https://clojars.org/clj-webdriver/versions/0.7.1

Step 4 - No diretório do seu projeto, crie outro diretório chamado features e crie um arquivo chamado 'config.clj'.

Step 5 - Em seguida, adicione o seguinte código ao arquivo 'config.clj' criado na etapa anterior.

ns clj-webdriver-tutorial.features.config)
(def test-port 3000)
(def test-host "localhost")
(def test-base-url (str "http://" test-host ":" test-port "/"))

O código acima basicamente diz à estrutura de teste da web para testar o aplicativo, que é carregado no URL http://localhost:3000

Step 6 - Por fim, vamos escrever nosso código para realizar nosso teste.

(ns clj-webdriver-tutorial.features.homepage
   (:require [clojure.test :refer :all]
      [ring.adapter.jetty :refer [run-jetty]]
      [clj-webdriver.taxi :refer :all]
      [clj-webdriver-tutorial.features.config :refer :all]
      [clj-webdriver-tutorial.handler :refer [app-routes]]))
(ns clj-webdriver-tutorial.features.homepage
   (:require [clojure.test :refer :all]
      [ring.adapter.jetty :refer [run-jetty]]
      [clj-webdriver.taxi :refer :all]
      [clj-webdriver-tutorial.features.config :refer :all]
      [clj-webdriver-tutorial.handler :refer [app-routes]]))
(defn start-server []
   (loop [server (run-jetty app-routes {:port test-port, :join? false})]
      (if (.isStarted server)
         server
         (recur server))))
(defn stop-server [server]
   (.stop server))
(defn start-browser []
   (set-driver! {:browser :firefox}))
(defn stop-browser []
   (quit))
(deftest homepage-greeting
   (let [server (start-server)]
      (start-browser)
      (to test-base-url)
      (is (= (text "body") "Hello World"))
      (stop-browser)
      (stop-server server)))

O código acima irá realizar as seguintes ações -

  • Inicie o servidor para o aplicativo.
  • Abra o caminho raiz no navegador.
  • Verifique se a mensagem "Hello World" está presente na página.
  • Feche o navegador.
  • Desligue o servidor.

Uma coisa que torna a biblioteca Clojure tão poderosa é o número de bibliotecas disponíveis para o framework Clojure. Já vimos muitas bibliotecas usadas em nossos exemplos anteriores para teste da web, desenvolvimento da web, desenvolvimento de aplicativos baseados em swing, a biblioteca jdbc para conexão com bancos de dados MySQL. A seguir estão apenas alguns exemplos de mais algumas bibliotecas.

data.xml

Esta biblioteca permite que Clojure trabalhe com dados XML. A versão da biblioteca a ser usada é org.clojure / data.xml "0.0.8". O data.xml oferece suporte para análise e emissão de XML. As funções de análise lerão XML de um Reader ou InputStream.

Exemplo

A seguir está um exemplo do processamento de dados de uma string para XML.

(ns clojure.examples.example
   (use 'clojure.data.xml)
   (:gen-class))
(defn Example []
   (let [input-xml (java.io.StringReader. "<?xml version = \"1.0\"
      encoding = \"UTF-8\"?><example><clo><Tutorial>The Tutorial
      value</Tutorial></clo></example>")]
      (parse input-xml)))

#clojure.data.xml.Element{
   :tag :example, :attrs {}, :content (#clojure.data.xml.Element {
      :tag :clo, :attrs {}, :content (#clojure.data.xml.Element {
         :tag :Tutorial, :attrs {},:content ("The Tutorial value")})})}
(Example)

data.json

Esta biblioteca permite que Clojure trabalhe com dados JSON. A versão da biblioteca a ser usada é org.clojure / data.json "0.2.6".

Exemplo

A seguir está um exemplo do uso desta biblioteca.

(ns clojure.examples.example
   (:require [clojure.data.json :as json])
   (:gen-class))
(defn Example []
   (println (json/write-str {:a 1 :b 2})))
(Example)

Resultado

O programa acima produz a seguinte saída.

{\"a\":1,\"b\":2}

data.csv

Esta biblioteca permite que Clojure trabalhe com ‘csv’dados. A versão da biblioteca a ser usada é org.clojure / data.csv "0.1.3".

Exemplo

A seguir está um exemplo do uso desta biblioteca.

(ns clojure.examples.example
   (require '[clojure.data.csv :as csv]
      '[clojure.java.io :as io])
   (:gen-class))
(defn Example []
   (with-open [in-file (io/reader "in-file.csv")]
      (doall
      (csv/read-csv in-file)))
   (with-open [out-file (io/writer "out-file.csv")]
   (csv/write-csv out-file
      [[":A" "a"]
      [":B" "b"]])))
(Example)

No código acima, a função 'csv' lerá primeiro um arquivo chamado in-file.csve coloque todos os dados na variável no arquivo. Em seguida, estamos usando a função write-csv para gravar todos os dados em um arquivo chamadoout-file.csv.