2014-12-26 13:56:36 +03:00
|
|
|
---
|
|
|
|
language: "Common Lisp"
|
2014-12-26 14:06:38 +03:00
|
|
|
filename: commonlisp-pt.lisp
|
2014-12-26 13:56:36 +03:00
|
|
|
contributors:
|
|
|
|
- ["Paul Nathan", "https://github.com/pnathan"]
|
2014-12-26 14:06:38 +03:00
|
|
|
translators:
|
|
|
|
- ["Édipo Luis Féderle", "https://github.com/edipofederle"]
|
2015-01-13 23:09:14 +03:00
|
|
|
lang: pt-br
|
2014-12-26 13:56:36 +03:00
|
|
|
---
|
|
|
|
|
|
|
|
ANSI Common Lisp é uma linguagem de uso geral, multi-paradigma, designada
|
|
|
|
para uma variedade de aplicações na indústria. É frequentemente citada
|
|
|
|
como uma linguagem de programação programável.
|
|
|
|
|
|
|
|
|
2014-12-26 14:15:03 +03:00
|
|
|
O ponto inicial clássico é [Practical Common Lisp e livremente disponível](http://www.gigamonkeys.com/book/)
|
2014-12-26 13:56:36 +03:00
|
|
|
|
|
|
|
Outro livro recente e popular é o
|
|
|
|
[Land of Lisp](http://landoflisp.com/).
|
|
|
|
|
|
|
|
|
|
|
|
```common_lisp
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;; 0. Sintaxe
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
;;; "Form" Geral
|
|
|
|
|
|
|
|
|
|
|
|
;; Lisp tem dois pedaços fundamentais de sintaxe: o ATOM e S-expression.
|
|
|
|
;; Tipicamente, S-expressions agrupadas são chamadas de `forms`.
|
|
|
|
|
|
|
|
|
2014-12-26 14:06:38 +03:00
|
|
|
10 ; um atom; é avaliado para ele mesmo
|
2014-12-26 13:56:36 +03:00
|
|
|
|
|
|
|
:THING ;Outro atom; avaliado para o símbolo :thing.
|
|
|
|
|
|
|
|
t ; outro atom, denotado true.
|
|
|
|
|
|
|
|
(+ 1 2 3 4) ; uma s-expression
|
|
|
|
|
|
|
|
'(4 :foo t) ;outra s-expression
|
|
|
|
|
|
|
|
|
|
|
|
;;; Comentários
|
|
|
|
|
|
|
|
;; Comentários de uma única linha começam com ponto e vírgula; usar dois para
|
|
|
|
;; comentários normais, três para comentários de seção, e quadro para comentários
|
|
|
|
;; em nível de arquivo.
|
|
|
|
|
|
|
|
#| Bloco de comentário
|
|
|
|
pode abranger várias linhas e...
|
|
|
|
#|
|
|
|
|
eles podem ser aninhados
|
|
|
|
|#
|
|
|
|
|#
|
|
|
|
|
|
|
|
;;; Ambiente
|
|
|
|
|
|
|
|
;; Existe uma variedade de implementações; a maioria segue o padrão.
|
|
|
|
;; CLISP é um bom ponto de partida.
|
|
|
|
|
2014-12-26 14:15:03 +03:00
|
|
|
;; Bibliotecas são gerenciadas através do Quicklisp.org's Quicklisp sistema.
|
2014-12-26 13:56:36 +03:00
|
|
|
|
|
|
|
;; Common Lisp é normalmente desenvolvido com um editor de texto e um REPL
|
|
|
|
;; (Read Evaluate Print Loop) rodando ao mesmo tempo. O REPL permite exploração
|
|
|
|
;; interativa do programa como ele é "ao vivo" no sistema.
|
|
|
|
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;;; 1. Tipos Primitivos e Operadores
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
;;; Símbolos
|
|
|
|
|
2014-12-26 14:15:03 +03:00
|
|
|
'foo ; => FOO Perceba que um símbolo é automáticamente convertido para maiúscula.
|
2014-12-26 13:56:36 +03:00
|
|
|
|
|
|
|
;; Intern manualmente cria um símbolo a partir de uma string.
|
|
|
|
|
|
|
|
(intern "AAAA") ; => AAAA
|
|
|
|
|
|
|
|
(intern "aaa") ; => |aaa|
|
|
|
|
|
|
|
|
;;; Números
|
|
|
|
9999999999999999999999 ; inteiro
|
|
|
|
#b111 ; binário => 7
|
|
|
|
#o111 ; octal => 73
|
|
|
|
#x111 ; hexadecimal => 273
|
|
|
|
3.14159s0 ; single
|
|
|
|
3.14159d0 ; double
|
|
|
|
1/2 ; ratios
|
|
|
|
#C(1 2) ; números complexos
|
|
|
|
|
|
|
|
|
|
|
|
;; Funções são escritas como (f x y z ...)
|
|
|
|
;; onde f é uma função e x, y, z, ... são operadores
|
|
|
|
;; Se você quiser criar uma lista literal de dados, use ' para evitar
|
|
|
|
;; que a lista seja avaliada - literalmente, "quote" os dados.
|
|
|
|
'(+ 1 2) ; => (+ 1 2)
|
|
|
|
;; Você também pode chamar uma função manualmente:
|
|
|
|
(funcall #'+ 1 2 3) ; => 6
|
|
|
|
;; O mesmo para operações aritiméticas
|
|
|
|
(+ 1 1) ; => 2
|
|
|
|
(- 8 1) ; => 7
|
|
|
|
(* 10 2) ; => 20
|
|
|
|
(expt 2 3) ; => 8
|
|
|
|
(mod 5 2) ; => 1
|
|
|
|
(/ 35 5) ; => 7
|
|
|
|
(/ 1 3) ; => 1/3
|
|
|
|
(+ #C(1 2) #C(6 -4)) ; => #C(7 -2)
|
|
|
|
|
|
|
|
;;; Booleans
|
|
|
|
t ; para true (qualquer valor não nil é true)
|
|
|
|
nil ; para false - e para lista vazia
|
|
|
|
(not nil) ; => t
|
|
|
|
(and 0 t) ; => t
|
|
|
|
(or 0 nil) ; => 0
|
|
|
|
|
|
|
|
;;; Caracteres
|
|
|
|
#\A ; => #\A
|
|
|
|
#\λ ; => #\GREEK_SMALL_LETTER_LAMDA
|
|
|
|
#\u03BB ; => #\GREEK_SMALL_LETTER_LAMDA
|
|
|
|
|
|
|
|
;;; String são arrays de caracteres com tamanho fixo.
|
|
|
|
"Hello, world!"
|
|
|
|
"Benjamin \"Bugsy\" Siegel" ; barra é um escape de caracter
|
|
|
|
|
|
|
|
;; String podem ser concatenadas também!
|
|
|
|
(concatenate 'string "Hello " "world!") ; => "Hello world!"
|
|
|
|
|
|
|
|
;; Uma String pode ser tratada como uma sequência de caracteres
|
|
|
|
(elt "Apple" 0) ; => #\A
|
|
|
|
|
|
|
|
;; format pode ser usado para formatar strings
|
|
|
|
(format nil "~a can be ~a" "strings" "formatted")
|
|
|
|
|
|
|
|
;; Impimir é bastante fácil; ~% indica nova linha
|
|
|
|
(format t "Common Lisp is groovy. Dude.~%")
|
|
|
|
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; 2. Variáveis
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; Você pode criar uma global (escopo dinâmico) usando defparameter
|
|
|
|
;; um nome de variável pode conter qualquer caracter, exceto: ()",'`;#|\
|
|
|
|
|
|
|
|
;; Variáveis de escopo dinâmico devem ter asteriscos em seus nomes!
|
|
|
|
|
|
|
|
(defparameter *some-var* 5)
|
|
|
|
*some-var* ; => 5
|
|
|
|
|
|
|
|
;; Você pode usar caracteres unicode também.
|
|
|
|
(defparameter *AΛB* nil)
|
|
|
|
|
|
|
|
|
|
|
|
;; Acessando uma variável anteriormente não ligada é um
|
|
|
|
;; comportamento não definido (mas possível). Não faça isso.
|
|
|
|
|
|
|
|
;; Ligação local: `me` é vinculado com "dance with you" somente dentro
|
|
|
|
;; de (let ... ). Let permite retornar o valor do último `form` no form let.
|
|
|
|
|
|
|
|
(let ((me "dance with you"))
|
|
|
|
me)
|
|
|
|
;; => "dance with you"
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; 3. Estruturas e Coleções
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
;; Estruturas
|
|
|
|
(defstruct dog name breed age)
|
|
|
|
(defparameter *rover*
|
|
|
|
(make-dog :name "rover"
|
|
|
|
:breed "collie"
|
|
|
|
:age 5))
|
|
|
|
*rover* ; => #S(DOG :NAME "rover" :BREED "collie" :AGE 5)
|
|
|
|
|
|
|
|
(dog-p *rover*) ; => t ;; ewww)
|
|
|
|
(dog-name *rover*) ; => "rover"
|
|
|
|
|
2014-12-26 14:19:21 +03:00
|
|
|
;; Dog-p, make-dog, e dog-name foram todas criadas por defstruct!
|
2014-12-26 13:56:36 +03:00
|
|
|
|
|
|
|
;;; Pares
|
|
|
|
;; `cons' constroi pares, `car' and `cdr' extrai o primeiro
|
|
|
|
;; e o segundo elemento
|
|
|
|
(cons 'SUBJECT 'VERB) ; => '(SUBJECT . VERB)
|
|
|
|
(car (cons 'SUBJECT 'VERB)) ; => SUBJECT
|
|
|
|
(cdr (cons 'SUBJECT 'VERB)) ; => VERB
|
|
|
|
|
|
|
|
;;; Listas
|
|
|
|
|
|
|
|
;; Listas são estruturas de dados do tipo listas encadeadas, criadas com `cons'
|
|
|
|
;; pares e terminam `nil' (ou '()) para marcar o final da lista
|
|
|
|
(cons 1 (cons 2 (cons 3 nil))) ; => '(1 2 3)
|
|
|
|
;; `list' é um construtor conveniente para listas
|
|
|
|
(list 1 2 3) ; => '(1 2 3)
|
|
|
|
;; e a quote (') também pode ser usado para um valor de lista literal
|
|
|
|
'(1 2 3) ; => '(1 2 3)
|
|
|
|
|
|
|
|
;; Ainda pode-se usar `cons' para adicionar um item no começo da lista.
|
|
|
|
(cons 4 '(1 2 3)) ; => '(4 1 2 3)
|
|
|
|
|
|
|
|
;; Use `append' para - surpreendentemente - juntar duas listas
|
|
|
|
(append '(1 2) '(3 4)) ; => '(1 2 3 4)
|
|
|
|
|
|
|
|
;; Ou use concatenate -
|
|
|
|
|
|
|
|
(concatenate 'list '(1 2) '(3 4))
|
|
|
|
|
|
|
|
;; Listas são um tipo muito central, então existe uma grande variedade de
|
|
|
|
;; funcionalidades para eles, alguns exemplos:
|
|
|
|
(mapcar #'1+ '(1 2 3)) ; => '(2 3 4)
|
|
|
|
(mapcar #'+ '(1 2 3) '(10 20 30)) ; => '(11 22 33)
|
|
|
|
(remove-if-not #'evenp '(1 2 3 4)) ; => '(2 4)
|
|
|
|
(every #'evenp '(1 2 3 4)) ; => nil
|
|
|
|
(some #'oddp '(1 2 3 4)) ; => T
|
|
|
|
(butlast '(subject verb object)) ; => (SUBJECT VERB)
|
|
|
|
|
|
|
|
|
|
|
|
;;; Vetores
|
|
|
|
|
|
|
|
;; Vector's literais são arrays de tamanho fixo.
|
|
|
|
#(1 2 3) ; => #(1 2 3)
|
|
|
|
|
|
|
|
;; Use concatenate para juntar dois vectors
|
|
|
|
(concatenate 'vector #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6)
|
|
|
|
|
|
|
|
;;; Arrays
|
|
|
|
|
|
|
|
;; Ambos vetores e strings são um caso especial de arrays.
|
|
|
|
|
|
|
|
;; 2D arrays
|
|
|
|
|
|
|
|
(make-array (list 2 2))
|
|
|
|
|
|
|
|
;; (make-array '(2 2)) também funciona.
|
|
|
|
|
|
|
|
; => #2A((0 0) (0 0))
|
|
|
|
|
|
|
|
(make-array (list 2 2 2))
|
|
|
|
|
|
|
|
; => #3A(((0 0) (0 0)) ((0 0) (0 0)))
|
|
|
|
|
|
|
|
;; Cuidado - os valores de inicialição padrões são
|
|
|
|
;; definidos pela implementção. Aqui vai como defini-lós.
|
|
|
|
|
|
|
|
(make-array '(2) :initial-element 'unset)
|
|
|
|
|
|
|
|
; => #(UNSET UNSET)
|
|
|
|
|
|
|
|
;; E, para acessar o element em 1,1,1 -
|
|
|
|
(aref (make-array (list 2 2 2)) 1 1 1)
|
|
|
|
|
|
|
|
; => 0
|
|
|
|
|
|
|
|
;;; Vetores Ajustáveis
|
|
|
|
|
|
|
|
;; Vetores ajustáveis tem a mesma representação impressa que os vectores
|
|
|
|
;; de tamanho fixo
|
|
|
|
(defparameter *adjvec* (make-array '(3) :initial-contents '(1 2 3)
|
|
|
|
:adjustable t :fill-pointer t))
|
|
|
|
|
|
|
|
*adjvec* ; => #(1 2 3)
|
|
|
|
|
|
|
|
;; Adicionando novo elemento
|
|
|
|
(vector-push-extend 4 *adjvec*) ; => 3
|
|
|
|
|
|
|
|
*adjvec* ; => #(1 2 3 4)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;; Ingenuamente, conjuntos são apenas listas:
|
|
|
|
|
|
|
|
(set-difference '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1)
|
|
|
|
(intersection '(1 2 3 4) '(4 5 6 7)) ; => 4
|
|
|
|
(union '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1 4 5 6 7)
|
|
|
|
(adjoin 4 '(1 2 3 4)) ; => (1 2 3 4)
|
|
|
|
|
|
|
|
;; Mas você irá querer usar uma estrutura de dados melhor que uma lista encadeada.
|
|
|
|
;; para performance.
|
|
|
|
|
|
|
|
;;; Dicionários são implementados como hash tables
|
|
|
|
|
|
|
|
;; Cria um hash table
|
|
|
|
(defparameter *m* (make-hash-table))
|
|
|
|
|
|
|
|
;; seta um valor
|
|
|
|
(setf (gethash 'a *m*) 1)
|
|
|
|
|
|
|
|
;; Recupera um valor
|
|
|
|
(gethash 'a *m*) ; => 1, t
|
|
|
|
|
|
|
|
;; Detalhe - Common Lisp tem multiplos valores de retorno possíveis. gethash
|
|
|
|
;; retorna t no segundo valor se alguma coisa foi encontrada, e nil se não.
|
|
|
|
|
|
|
|
;; Recuperando um valor não presente retorna nil
|
|
|
|
(gethash 'd *m*) ;=> nil, nil
|
|
|
|
|
|
|
|
;; Você pode fornecer um valor padrão para uma valores não encontrados
|
|
|
|
(gethash 'd *m* :not-found) ; => :NOT-FOUND
|
|
|
|
|
|
|
|
;; Vamos tratas múltiplos valores de rotorno aqui.
|
|
|
|
|
|
|
|
(multiple-value-bind
|
|
|
|
(a b)
|
|
|
|
(gethash 'd *m*)
|
|
|
|
(list a b))
|
|
|
|
; => (NIL NIL)
|
|
|
|
|
|
|
|
(multiple-value-bind
|
|
|
|
(a b)
|
|
|
|
(gethash 'a *m*)
|
|
|
|
(list a b))
|
|
|
|
; => (1 T)
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; 3. Funções
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
;; Use `lambda' para criar funções anônimas
|
|
|
|
;; Uma função sempre retorna um valor da última expressão avaliada.
|
|
|
|
;; A representação exata impressão de uma função varia de acordo ...
|
|
|
|
|
|
|
|
(lambda () "Hello World") ; => #<FUNCTION (LAMBDA ()) {1004E7818B}>
|
|
|
|
|
|
|
|
;; Use funcall para chamar uma função lambda.
|
|
|
|
(funcall (lambda () "Hello World")) ; => "Hello World"
|
|
|
|
|
|
|
|
;; Ou Apply
|
|
|
|
(apply (lambda () "Hello World") nil) ; => "Hello World"
|
|
|
|
|
|
|
|
;; "De-anonymize" a função
|
|
|
|
(defun hello-world ()
|
|
|
|
"Hello World")
|
|
|
|
(hello-world) ; => "Hello World"
|
|
|
|
|
|
|
|
;; O () acima é a lista de argumentos da função.
|
|
|
|
(defun hello (name)
|
|
|
|
(format nil "Hello, ~a " name))
|
|
|
|
|
|
|
|
(hello "Steve") ; => "Hello, Steve"
|
|
|
|
|
|
|
|
;; Funções podem ter argumentos opcionais; eles são nil por padrão
|
|
|
|
|
|
|
|
(defun hello (name &optional from)
|
|
|
|
(if from
|
|
|
|
(format t "Hello, ~a, from ~a" name from)
|
|
|
|
(format t "Hello, ~a" name)))
|
|
|
|
|
|
|
|
(hello "Jim" "Alpacas") ;; => Hello, Jim, from Alpacas
|
|
|
|
|
|
|
|
;; E os padrões podem ser configurados...
|
|
|
|
(defun hello (name &optional (from "The world"))
|
|
|
|
(format t "Hello, ~a, from ~a" name from))
|
|
|
|
|
|
|
|
(hello "Steve")
|
|
|
|
; => Hello, Steve, from The world
|
|
|
|
|
|
|
|
(hello "Steve" "the alpacas")
|
|
|
|
; => Hello, Steve, from the alpacas
|
|
|
|
|
|
|
|
|
|
|
|
;; E é claro, palavras-chaves são permitidas também... frequentemente mais
|
|
|
|
;; flexivel que &optional.
|
|
|
|
|
|
|
|
(defun generalized-greeter (name &key (from "the world") (honorific "Mx"))
|
|
|
|
(format t "Hello, ~a ~a, from ~a" honorific name from))
|
|
|
|
|
|
|
|
(generalized-greeter "Jim") ; => Hello, Mx Jim, from the world
|
|
|
|
|
|
|
|
(generalized-greeter "Jim" :from "the alpacas you met last summer" :honorific "Mr")
|
|
|
|
; => Hello, Mr Jim, from the alpacas you met last summer
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; 4. Igualdade
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
;; Common Lisp tem um sistema sofisticado de igualdade. Alguns são cobertos aqui.
|
|
|
|
|
|
|
|
;; Para número use `='
|
|
|
|
(= 3 3.0) ; => t
|
|
|
|
(= 2 1) ; => nil
|
|
|
|
|
|
|
|
;; para identidade de objeto (aproximadamente) use `eql`
|
|
|
|
(eql 3 3) ; => t
|
|
|
|
(eql 3 3.0) ; => nil
|
|
|
|
(eql (list 3) (list 3)) ; => nil
|
|
|
|
|
|
|
|
;; para listas, strings, e para pedaços de vetores use `equal'
|
|
|
|
(equal (list 'a 'b) (list 'a 'b)) ; => t
|
|
|
|
(equal (list 'a 'b) (list 'b 'a)) ; => nil
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; 5. Fluxo de Controle
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
;;; Condicionais
|
|
|
|
|
|
|
|
(if t ; testa a expressão
|
|
|
|
"this is true" ; então expressão
|
|
|
|
"this is false") ; senão expressão
|
|
|
|
; => "this is true"
|
|
|
|
|
|
|
|
;; Em condicionais, todos valores não nulos são tratados como true
|
|
|
|
(member 'Groucho '(Harpo Groucho Zeppo)) ; => '(GROUCHO ZEPPO)
|
|
|
|
(if (member 'Groucho '(Harpo Groucho Zeppo))
|
|
|
|
'yep
|
|
|
|
'nope)
|
|
|
|
; => 'YEP
|
|
|
|
|
|
|
|
;; `cond' encadeia uma série de testes para selecionar um resultado
|
|
|
|
(cond ((> 2 2) (error "wrong!"))
|
|
|
|
((< 2 2) (error "wrong again!"))
|
|
|
|
(t 'ok)) ; => 'OK
|
|
|
|
|
2014-12-26 14:15:03 +03:00
|
|
|
;; Typecase é um condicional que escolhe uma de seus cláusulas com base do tipo
|
|
|
|
;; do seu valor
|
2014-12-26 13:56:36 +03:00
|
|
|
|
|
|
|
(typecase 1
|
|
|
|
(string :string)
|
|
|
|
(integer :int))
|
|
|
|
|
|
|
|
; => :int
|
|
|
|
|
|
|
|
;;; Interação
|
|
|
|
|
|
|
|
;; Claro que recursão é suportada:
|
|
|
|
|
|
|
|
(defun walker (n)
|
|
|
|
(if (zerop n)
|
|
|
|
:walked
|
|
|
|
(walker (1- n))))
|
|
|
|
|
|
|
|
(walker 5) ; => :walked
|
|
|
|
|
|
|
|
;; Na maioria das vezes, nós usamos DOTLISO ou LOOP
|
|
|
|
|
|
|
|
(dolist (i '(1 2 3 4))
|
|
|
|
(format t "~a" i))
|
|
|
|
|
|
|
|
; => 1234
|
|
|
|
|
|
|
|
(loop for i from 0 below 10
|
|
|
|
collect i)
|
|
|
|
|
|
|
|
; => (0 1 2 3 4 5 6 7 8 9)
|
|
|
|
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; 6. Mutação
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
;; Use `setf' para atribuir um novo valor para uma variável existente. Isso foi
|
|
|
|
;; demonstrado anteriormente no exemplo da hash table.
|
|
|
|
|
|
|
|
(let ((variable 10))
|
|
|
|
(setf variable 2))
|
|
|
|
; => 2
|
|
|
|
|
|
|
|
|
|
|
|
;; Um bom estilo Lisp é para minimizar funções destrutivas e para evitar
|
|
|
|
;; mutação quando razoável.
|
|
|
|
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; 7. Classes e Objetos
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
;; Sem clases Animal, vamos usar os veículos de transporte de tração
|
|
|
|
;; humana mecânicos.
|
|
|
|
|
|
|
|
(defclass human-powered-conveyance ()
|
|
|
|
((velocity
|
|
|
|
:accessor velocity
|
|
|
|
:initarg :velocity)
|
|
|
|
(average-efficiency
|
|
|
|
:accessor average-efficiency
|
|
|
|
:initarg :average-efficiency))
|
|
|
|
(:documentation "A human powered conveyance"))
|
|
|
|
|
|
|
|
;; defcalss, seguido do nome, seguido por uma list de superclass,
|
|
|
|
;; seguido por um uma 'slot list', seguido por qualidades opcionais como
|
|
|
|
;; :documentation
|
|
|
|
|
|
|
|
;; Quando nenhuma lista de superclasse é setada, uma lista padrão para
|
|
|
|
;; para o objeto padrão é usada. Isso *pode* ser mudado, mas não até você
|
|
|
|
;; saber o que está fazendo. Olhe em Art of the Metaobject Protocol
|
|
|
|
;; para maiores informações.
|
|
|
|
|
|
|
|
(defclass bicycle (human-powered-conveyance)
|
|
|
|
((wheel-size
|
|
|
|
:accessor wheel-size
|
|
|
|
:initarg :wheel-size
|
|
|
|
:documentation "Diameter of the wheel.")
|
|
|
|
(height
|
|
|
|
:accessor height
|
|
|
|
:initarg :height)))
|
|
|
|
|
|
|
|
(defclass recumbent (bicycle)
|
|
|
|
((chain-type
|
|
|
|
:accessor chain-type
|
|
|
|
:initarg :chain-type)))
|
|
|
|
|
|
|
|
(defclass unicycle (human-powered-conveyance) nil)
|
|
|
|
|
|
|
|
(defclass canoe (human-powered-conveyance)
|
|
|
|
((number-of-rowers
|
|
|
|
:accessor number-of-rowers
|
|
|
|
:initarg :number-of-rowers)))
|
|
|
|
|
|
|
|
|
|
|
|
;; Chamando DESCRIBE na classe human-powered-conveyance no REPL dá:
|
|
|
|
|
|
|
|
(describe 'human-powered-conveyance)
|
|
|
|
|
|
|
|
; COMMON-LISP-USER::HUMAN-POWERED-CONVEYANCE
|
|
|
|
; [symbol]
|
|
|
|
;
|
|
|
|
; HUMAN-POWERED-CONVEYANCE names the standard-class #<STANDARD-CLASS
|
|
|
|
; HUMAN-POWERED-CONVEYANCE>:
|
|
|
|
; Documentation:
|
|
|
|
; A human powered conveyance
|
|
|
|
; Direct superclasses: STANDARD-OBJECT
|
|
|
|
; Direct subclasses: UNICYCLE, BICYCLE, CANOE
|
|
|
|
; Not yet finalized.
|
|
|
|
; Direct slots:
|
|
|
|
; VELOCITY
|
|
|
|
; Readers: VELOCITY
|
|
|
|
; Writers: (SETF VELOCITY)
|
|
|
|
; AVERAGE-EFFICIENCY
|
|
|
|
; Readers: AVERAGE-EFFICIENCY
|
|
|
|
; Writers: (SETF AVERAGE-EFFICIENCY)
|
|
|
|
|
|
|
|
;; Note o comportamento reflexivo disponível para você! Common Lisp é
|
|
|
|
;; projetada para ser um sistema interativo.
|
|
|
|
|
|
|
|
;; Para definir um métpdo, vamos encontrar o que nossa cirunferência da
|
|
|
|
;; roda da bicicleta usando a equação: C = d * pi
|
|
|
|
|
|
|
|
(defmethod circumference ((object bicycle))
|
|
|
|
(* pi (wheel-size object)))
|
|
|
|
|
|
|
|
;; pi já é definido para a gente em Lisp!
|
|
|
|
|
|
|
|
;; Vamos supor que nós descobrimos que o valor da eficiência do número
|
2014-12-26 14:15:03 +03:00
|
|
|
;; de remadores em uma canoa é aproximadamente logarítmica. Isso provavelmente
|
|
|
|
;; deve ser definido no construtor / inicializador.
|
2014-12-26 13:56:36 +03:00
|
|
|
|
|
|
|
;; Veja como initializar sua instância após Common Lisp ter construído isso:
|
|
|
|
|
|
|
|
(defmethod initialize-instance :after ((object canoe) &rest args)
|
|
|
|
(setf (average-efficiency object) (log (1+ (number-of-rowers object)))))
|
|
|
|
|
|
|
|
;; Em seguida, para a construção de uma ocorrência e verificar a eficiência média ...
|
|
|
|
|
|
|
|
(average-efficiency (make-instance 'canoe :number-of-rowers 15))
|
|
|
|
; => 2.7725887
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; 8. Macros
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
|
|
;; Macros permitem que você estenda a sintaxe da lingaugem
|
|
|
|
|
2014-12-26 14:15:03 +03:00
|
|
|
;; Common Lisp não vem com um loop WHILE - vamos adicionar um.
|
2014-12-26 13:56:36 +03:00
|
|
|
;; Se obedecermos nossos instintos 'assembler', acabamos com:
|
|
|
|
|
|
|
|
(defmacro while (condition &body body)
|
|
|
|
"Enquanto `condition` é verdadeiro, `body` é executado.
|
|
|
|
|
|
|
|
`condition` é testado antes de cada execução do `body`"
|
|
|
|
(let ((block-name (gensym)))
|
|
|
|
`(tagbody
|
|
|
|
(unless ,condition
|
|
|
|
(go ,block-name))
|
|
|
|
(progn
|
|
|
|
,@body)
|
|
|
|
,block-name)))
|
|
|
|
|
|
|
|
;; Vamos dar uma olhada em uma versão alto nível disto:
|
|
|
|
|
|
|
|
|
|
|
|
(defmacro while (condition &body body)
|
|
|
|
"Enquanto `condition` for verdadeira, `body` é executado.
|
|
|
|
|
|
|
|
`condition` é testado antes de cada execução do `body`"
|
|
|
|
`(loop while ,condition
|
|
|
|
do
|
|
|
|
(progn
|
|
|
|
,@body)))
|
|
|
|
|
|
|
|
;; Entretanto, com um compilador moderno, isso não é preciso; o LOOP
|
|
|
|
;; 'form' compila igual e é bem mais fácil de ler.
|
|
|
|
|
|
|
|
;; Noteq ue ``` é usado , bem como `,` e `@`. ``` é um operador 'quote-type'
|
|
|
|
;; conhecido como 'quasiquote'; isso permite o uso de `,` . `,` permite "unquoting"
|
|
|
|
;; e variáveis. @ interpolará listas.
|
|
|
|
|
|
|
|
;; Gensym cria um símbolo único garantido que não existe em outras posições
|
|
|
|
;; o sistema. Isto é porque macros são expandidas em tempo de compilação e
|
|
|
|
;; variáveis declaradas na macro podem colidir com as variáveis usadas na
|
|
|
|
;; código regular.
|
|
|
|
|
|
|
|
;; Veja Practical Common Lisp para maiores informações sobre macros.
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Leitura Adicional
|
|
|
|
|
|
|
|
[Continua em frente com Practical Common Lisp book.](http://www.gigamonkeys.com/book/)
|
|
|
|
|
|
|
|
|
|
|
|
## Créditos
|
|
|
|
|
2014-12-26 14:19:21 +03:00
|
|
|
Muitos agradecimentos ao pessoal de Schema por fornecer um grande ponto de partida
|
2014-12-26 13:56:36 +03:00
|
|
|
o que facilitou muito a migração para Common Lisp.
|
|
|
|
|
2014-12-26 14:20:30 +03:00
|
|
|
- [Paul Khuong](https://github.com/pkhuong) pelas grandes revisões.
|