No SBCL REPL, por que entrar é '(nil . nil)
avaliado como (nil)
e não apenas nil
?
Se uma lista vazia é aquela onde ambos os "elementos" da célula cons estão nil
, por que eles não são iguais?
Minha suposição para isso é que a SBCL faz as seguintes avaliações:
(car '()) => nil
(cdr '()) => nil
(car '(nil . nil)) => nil
(cdr '(nil . nil)) => nil
E ainda:
'() => nil
'(nil . nil) => (nil)
car
ecdr
retornenil
se for dadonil
como argumento. Vamos predispor a palavranil
por um minuto e ver quais valores você está realmente observando.car
ecdr
obtivemos uma lista vazia, então retornamosnil
ou()
.Agora
(nil . nil)
é(() . ())
. Ou seja, é uma célula de contras cujo carro e cdr são ambosnil
.Quando temos a
. ()
no final de uma célula cons, podemos encurtá-la notacionalmente, omitindo o finalnil
. Esta é apenas uma conveniência de notação, portanto, pela nossa notação,(() . ())
pode ser escrito como(())
ou(nil)
. Observe que isso não altera o valor. A maneira mais explícita de escrevê-lo ainda é(() . ())
, mas também podemos escrevê-lo de forma mais curta para facilitar a leitura.Isso não está correto. Uma lista vazia não é uma célula contra. Uma lista vazia é o átomo
nil
. É um símbolo, assim como'foo
ou'pizza
ou'common-lisp
. É apenas um símbolo que escolhemos usar para esse fim. Masnil
não tem carro nem celular CDR. Acontece que muitas vezes é conveniente deixar(car nil)
e(cdr nil)
sernil
como casos extremos de algoritmos, de modo que as funçõescar
ecdr
tenham um comportamento especial emnil
. Mas nãonil
é uma célula contra.Pela classe do sistema
LIST
, olist
tipo pode ser descrito comoPortanto, uma lista em Common Lisp é definida como "uma célula cons ou o valor especial
nil
". Notavelmente,nil
não é em si uma célula contra.Isso não é específico do SBCL. Está definido no padrão Common Lisp.
NILs em uma célula contras
Observe que
NIL
e()
são o mesmo objeto , apenas escritos de forma diferente:Observe também que você não avalia
(nil . nil)
, mas'(nil . nil)
. O primeiro não é um código Lisp válido. O último é, porque é uma expressão s citada sintaticamente correta.(nil . nil)
é igual a(nil)
, mas escrito de forma diferente. A estrutura de contras é igual .As expressões s acima são iguais :
CAR e C****R de NIL
Todas as operações cxxxxr
NIL
do Common Lisp são definidas para retornar , quando chamadas com uma lista vazia (-> o símbolo/listaNIL
):Veja Acessador CAR, CDR, CAAR, CADR, CDAR, CDDR, CAAAR, CAADR, CADAR, CADDR, CDAAR, CDADR, CDDAR, CDDDR, CAAAAR, CAAADR, CAADAR, CAADDR, CADAAR, CADADR, CADDAR, CADDDR, CDAAAR, CDAADR, CDADAR, CDADDR, CDDAAR, CDDADR, CDDDAR, CDDDDR no padrão Common Lisp.
Diferenças da função
car
entre linguagens Common Lisp e SchemeIsso é diferente da linguagem de programação Scheme, onde
(car '())
há um erro. Veja por exemplo R7RS carro pequeno .Observe também que Scheme não possui
nil
. É indefinido na linguagem e, portanto, não é o mesmo que a lista vazia()
. Avaliar uma lista vazia()
no Scheme é um erro.As seguintes expressões de esquema são avaliadas como um erro:
As três expressões acima serão avaliadas
NIL
em Common Lisp.O erro crítico que você cometeu aqui foi entender a implicação de maneira errada. Em particular, no Common Lisp é verdade que
car
ecdr
da lista vazia retorna a lista vazia, mas não é verdade que qualquer objeto para o qual isso seja verdade seja a lista vazia. Na verdade, está claro que isso não pode ser verdade porque o objeto da lista vazia é único, embora(eq (cons '() '()) (cons '() '()))
deva ser falso.Portanto, embora 'ser a lista vazia' implique (em Common Lisp!) que pegar
car
/cdr
retorna a lista vazia, o inverso não é verdadeiro.