https://lisp-lang.org ou https://common-lisp.net/downloads (common lisp)
https://common-lisp.net/downloads lisp online
https://clojure.org/index Clojure
1958
primeira linguagem funcional
primeiro REPL
vários dialetos
metaprogramcaçao ou macros
varias implementações (com diferenças)
scheme 1970
common lisp 1975 - virou o padrão
clojure 2005
racket 2010 - para criar outras linguagens de programação
Lisp é facilmente modificável e acaba incorporando ideias novas em programação
OO (1983 logo depois de Modula)
call with continuation
pattern matching
lazy evaluation(??)
etc
Entre pareteses, heterogenea, separa por brancos
(5 6 9.8 abobora () (5 6) "abc")
abobora
é um simbolo/atomo, como em prolog.
(funcao arg1 arg2 ...)
(operador arg1 arg2 ...)
(special-form arg1 arg2 ...)
(+ 4 5 6 (cos 4))
(if (> x 0) (* x 4) (- x 2))
Em outras linguagens de programação uma diferença é a sintaxe
if (a<b) a else b
if(a<b,a,b)
mas em lisp nao há diferença sintática
(if (> a b) a b)
(func (> a b) a b)
A diferença central é que funções sempre avaliam seus argumentos e comandos podem nao avaliar todos
(if (> a b) a (/ 1 0))
a > b
(/ 1 0)
não é avaliado e nao
da problema. Se fosse uma funçao (que avalia seus argumentos antes de
rodar - a nao ser o Haskell por causa do lazy!) isso daria
problema.versão simples
(let ()
exp1
exp2
...
expn)
avalia cada expressão na ordem. Retorna o valor da ultima expressão
versão com variáveis locais
(let ((var1 val1)
(var2 val2)
...
)
exp1
exp2
...
expn)
cria as variáveis locais var1
… e atribui os valores
val1
… (como no haskell)
(setf x exp)
avalia a expressão e atribui a variável
x
(local ou global)
define funções
(defun double (x)
(* x 2)
)
(defun aux (x y)
(let ((a (+ x y))
b
)
...
)
)
cons
gruda na frente de uma lista (:
do
haskell)
car
first
a cabeça da lista
cdr
rest
o resto da lista
null
testa se a lista é vazia
NIL
ou ()
lista vazia
append
gruda 2 ou mais listas
list
cria uma lista de seus argumentos
eq
eql
equal
equalp
=
testes de igualdade https://eli.thegreenplace.net/2004/08/08/equality-in-lisp
igualdades rapidas/atomicas O(1) eq
eql
=
e igualdades lógicas O(n) listas, etc
há o problema do caso infinito para igualdades lógicas
class X
pass
a = X()
a.nome = "jose"
a.dado = a
b = X()
b.nome = "jose"
b.dado = b
a==b
(defun reverte (lista)
(if (null lista) NIL
(append (reverte (rest lista))
(list (first lista)))
))
(defun revacc (lista acc)
(if (null lista) acc
(revacc (rest lista)
(cons (first lista) acc))
))
(defun trocatodos (novo velho lista)
(if (null lista) nil
(if (eql (first lista) velho)
(cons novo (trocatodos novo velho (rest lista)))
(cons (first lista) (trocatodos novo velho (rest lista)))
)
)
)
ou
(defun trocatodos (novo velho lista)
(if (null lista) nil
(let ((a (first lista))
(r (rest lista))
)
(if (eql a velho)
(cons novo (trocatodos novo velho r))
(cons a (trocatodos novo velho r))
)
)
)
)
ou ainda
(defun trocatodos (novo velho lista)
(if (null lista) nil
(let* ((a (first lista)) <---- let*
(r (rest lista))
(resto (trocatodos novo velho r))
)
(if (eql a velho)
(cons novo resto)
(cons a resto))
)))
os mesmos da 1a aula do haskell (e do prolog)
(defun separa (item lista)
(if (null lista) (list nil nil)
(if (eql item (first lista))
(list nil (rest lista))
(let* ((x (separa item (rest lista)))
(y (first x))
(z (rest x))
)
(cons (cons (first lista) y) z)
))))
(1 2 3)
não funciona, 1
não é uma
função/operador/forma especial
listas são avaliadas como expressões.
eu preciso desligar o avaliador para criar a lista (1 2 3)
(quote (1 2 3))
'(1 2 3)
ou
(list 1 2 3)
(cons 1 (cons 2 (cons 3 nil)))
Como (list 1 2 (+ 4 5))
avalia?
o 1o elemento da lista é uma funçao list
avalia cada um dos argumentos
números avaliam para eles mesmos 1 ==> 1
,
2 ==> 2
(+ 4 5)
é uma nova lista/ expressão. +
é uma função.
recursivamente avalia (+ 4 5)
para 9
roda o list
que cira uma lista com 1 2 e 9
retorna (1 2 9)
Outras coisas além de números avaliam para si mesmos
strings
nil avalia para ()
() avalia para si mesmo
‘T’ avalia para si mesmo (True)
simbolos começando com :
(keywords)
A avaliação de um simbolo retorna o valor armazenado (via let ou setf) no simbolo/variável
(setf x (+ 1 2))
x
(let ((x 99.7))
(print x))
quote simbolo retorna o simbolo: 'abc
retorna o simbolo
abc
variavies livres em funções.
(setf x 8)
(defun f1 (a) (+ x a))
(let ((x 100))
(f1 4))
==> 12
em python
x = 8
def f1 (a):
return x+a
def f2():
x = 100
f1(4)
f2()
==> 12
que é o comum em outras linguagens de programação. A variavel “livre”
x
de f1 vem do contexto sintatico onde a definição de
f1
esta. Nesse caso a variavel global.
Isto é o escopo estatico
Lisp permite o escopo dinamico
(defvar x 8) <--- declara um escopo dinamico para x
(defun f1 (a)
(+ x a))
(let ((x 100)) (f1 4))
==> 104
no segundo caso, o escopo de x
é
dinamico, e o valor usado será o último disponível na
pilha de execuçao.
(list 'if '(> x 0) (cons '* '(x 4))
(list '- 'x 2))
==>
(if (> x 0) (* x 4) (- x 2))
isso é o central na metaprogramação
“funções” que nao avaliam seus argumentos, mas geram uma lista usando esses argumentos, que é uma expressão Lisp. Essa lista gerada é avaliada ou compilada
(when teste a1 a2 .. an)
===> converte para
(if teste (let ()
a1 a2 .. an))
(defmacro when2 (teste &rest resto)
(list 'if teste (cons 'let (cons () resto)))
)
(macroexpand '(when2 (pos a) (incf a) (print a)))
(pyif teste t1 t2 t3 else: e1 e2)
==> converte para
(if teste (let () t1 t2 t3) (let () e1 e2))
(defmacro pyif (teste &rest resto)
(let* ((troca (separa `else: resto))
(pthen (first troca))
(pelse (second troca))
(xthen (if (null pthen) nil
(cons 'let (cons nil pthen))))
(xelse (if (null pelse) nil
(cons 'let (cons nil pelse))))
)
(list 'if teste xthen xelse)
))
define comportamentos na leitura para caracteres especias
'( a b c) ==> (quote (a b c))
quote
é uma forma especial que nao avalia seu argumento
e retorna ele
backquote - para macros
#'
para funções
#(1 2 3)
==> (vector 1 2 3)
etc
(defmacro when2 (teste &rest resto)
`(if ,teste
(let () ,@resto)
)
)
Se variáveis podem ter tanto um valor e uma função associada (lisp-2) ou apenas um valor (que pode ser uma função) (lisp-1)
python
soma1 = 6
def soma1 (a):
return a*2
x só pode ter um valor (e vira uma função no def)
common lisp
(setf soma1 6)
(defun soma1 (a) (+ 1 a))
common lisp é um lisp-2
scheme é um lisp-1
O problema de um lisp-2 sao as funções de alto nível
(map soma1 '(1 2 3 4))
em lisp-2 soma1
vai ser avaliado e retorna o valor
armazenado no simbolo e não a função definida.
é preciso uma forma especial que retorna a função associada a um simbolo
(map #'soma1 '(1 2 3))
como Scala, compila para JVM, e é compatível com bibliotecas e código já escrito em java
usado como linguagem principal(?) de desenvolvimento no Nubank https://building.nubank.com.br/clojure-15th-anniversary-a-retrospective/ que comprou a Clojure https://olhardigital.com.br/2020/07/24/pro/nubank-compra-criadora-das-linguagens-de-programacao-clojure-e-datomic/
mudanças sintáticas.
A mais importante é listas que não vão ser avaliadas (em
formas especiais) são trocadas por [ ]
(defun soma (x y)
(let ((soma (+ x y))
)
soma
))
(defn soma [x y]
(let [soma (+ x y)]
soma))
interoperabilidade com java: veja em https://clojure.org/guides/learn/functions Java Interop
vetores, dicionários, sets
uma implementação inicial de lisp é fácil.
processamento sinatico é facil - expressões estão entre ( e ) casados
implemente (no baixo nível) apenas alguns primitivos
atribuição (setf)
construção de lista (cons)
um condicional (if)
quote
definição de função anonima
macros
aplicação de uma função
operacoes aritmeticas em numeros e 2 funcoes em listas (cons, first e rest)
mais alguns poucas coisas….
Por exemplo https://homes.cs.aau.dk/~normark/prog3-03/html/notes/languages_themes-list-in-lisp.html
https://stackoverflow.com/questions/2664618/what-does-it-mean-that-lisp-can-be-written-in-itself
https://github.com/fluentpython/lispy/tree/main
As outras coisas são macros do próprio lisp
Meta-circular evaluator