Por que Clojure tem "palavras-chave" além de "símbolos"?

130

Eu tenho um conhecimento passageiro de outros Lisps (particularmente Scheme) desde o início. Recentemente, tenho lido sobre o Clojure . Vejo que ele possui "símbolos" e "palavras-chave". Símbolos que eu conheço, mas não com palavras-chave.

Outros Lisps têm palavras-chave? Qual é a diferença entre as palavras-chave e os símbolos que não possuem notação diferente (por exemplo: dois pontos)?

Laurence Gonsalves
fonte

Respostas:

139

Aqui está a documentação do Clojure para palavras-chave e símbolos.

Palavras-chave são identificadores simbólicos que se avaliam. Eles fornecem testes de igualdade muito rápidos ...

Símbolos são identificadores que normalmente são usados ​​para se referir a outra coisa. Eles podem ser usados ​​em formulários de programas para se referir a parâmetros de função, deixar ligações, nomes de classes e vars globais ...

Palavras-chave são geralmente usadas como "seqüências constantes" leves, por exemplo, para as chaves de um mapa de hash ou os valores de despacho de um método múltiplo. Os símbolos geralmente são usados ​​para nomear variáveis ​​e funções e é menos comum manipulá-los como objetos diretamente, exceto em macros e coisas do tipo. Mas não há nada que o impeça de usar um símbolo em todos os lugares em que você usa uma palavra-chave (se você não se importa de citá-las o tempo todo).

A maneira mais fácil de ver a diferença é ler Keyword.javae Symbol.javana fonte Clojure. Existem algumas diferenças óbvias na implementação. Por exemplo, um símbolo no Clojure pode ter metadados e uma palavra-chave não.

Além da sintaxe de dois pontos, você pode usar dois pontos para criar uma palavra-chave qualificada para namespace.

user> :foo
:foo
user> ::foo
:user/foo

O Lisp comum possui palavras-chave, assim como Ruby e outros idiomas. Eles são um pouco diferentes nessas línguas, é claro. Algumas diferenças entre as palavras-chave Common Lisp e as palavras-chave Clojure:

  1. Palavras-chave em Clojure não são símbolos.

    user> (symbol? :foo)  
    false
  2. As palavras-chave não pertencem a nenhum espaço para nome, a menos que você as qualifique especificamente:

    user> (namespace :foo)
    nil
    user> (namespace ::foo)
    "user"

(Obrigado Rainer Joswig por me dar idéias sobre o que examinar.)

Brian Carper
fonte
10
Isso explica quais são as diferenças, mas não porque duas construções diferentes são necessárias. Clojure não poderia ter criado algo com a união dos recursos da palavra-chave e do símbolo?
25
As palavras-chave são leves e têm uma sintaxe conveniente, acho que é tudo o que há para ela. O idioma funcionaria bem sem eles, mas é bom ter e é muito usado. Você não pode ter uma união de suas habilidades porque as Palavras-chave são sempre autoavaliadas (ou seja, você não pode usá-las como nomes de variáveis ​​ou funções) e os Símbolos em geral nem sempre podem ser autoavaliados.
22630 Brian Carper
1
Parece palavras-chave são mais úteis como chaves em HashMaps etc como eles não mudam, uma vez avaliados: (eval (eval ':a))vs (eval (eval ''a)). Existem outras vantagens? Desempenho sábio, eles são idênticos?
Kristianlm
5
(idêntico?: qwe: qwe) -> verdadeiro. (idêntico? 'qwe' qwe) -> false. Os símbolos usam cadeia interna, portanto, a comparação também é rápida.
precisa saber é
29

Lisp comum possui símbolos de palavras-chave.

Palavras-chave também são símbolos.

(symbolp ':foo) -> T

O que torna as palavras-chave especiais:

  • : foo é analisado pelo leitor Common Lisp como a palavra-chave do símbolo :: foo
  • as palavras-chave se avaliam:: foo ->: foo
  • o pacote inicial de símbolos de palavras-chave é o pacote KEYWORD: palavra-chave: foo ->: foo
  • as palavras-chave são exportadas do pacote KEYWORD
  • palavras-chave são constantes, não é permitido atribuir um valor diferente

Caso contrário, as palavras-chave são símbolos comuns. Portanto, as palavras-chave podem nomear funções ou ter listas de propriedades.

Lembre-se: no Common Lisp, os símbolos pertencem a um pacote. Isso pode ser escrito como:

  • foo, quando o símbolo estiver acessível no pacote atual
  • foo: bar, quando o símbolo FOO é exportado da embalagem BAR
  • foo :: bar, quando o símbolo FOO está no pacote BAR

Para símbolos de palavras-chave, significa que: foo, keyword: foo e keyword :: foo são todos o mesmo símbolo. Assim, as duas últimas notações geralmente não são usadas.

Assim: foo é apenas analisado para estar no pacote KEYWORD, assumindo que não dar nome ao pacote antes do nome do símbolo significa, por padrão, o pacote KEYWORD.

Rainer Joswig
fonte
6

Palavras-chave são símbolos que se avaliam, para que você não precise se lembrar de citá-las.

Greg Hewgill
fonte
5
É isso? Digitar: em vez de 'não parece ser uma grande vitória, especialmente porque: é um pressionamento de tecla extra na maioria dos teclados.
9607 Laurence Gonsalves #:
11
Bem, é mais do que apenas o personagem, na verdade. As palavras-chave permanecem nas palavras-chave após a avaliação, enquanto os símbolos são avaliados de acordo com o que eles vinculam. É mais como uma diferença semântica, porque eles geralmente são usados ​​para fins diferentes.
9119 Greg Hewgill
13
Palavras-chave não são símbolos em Clojure
David Plumpton
4

: keywords também são tratadas especialmente por muitas das coleções, permitindo uma sintaxe realmente conveniente.

(:user-id (get-users-map))

é o mesmo que

((get-users-map) :user-id)

isso torna as coisas um pouco mais flexíveis

Arthur Ulfeldt
fonte
21
Isso também é válido para os símbolos, ('a {' a 1 'b 2}) => 1 e ({' a 1 'b 2}' b) => 2. #
1111 Jonas
4

Para palavras-chave, os valores de hash são calculados e armazenados em cache quando a palavra-chave é construída pela primeira vez. Ao procurar uma palavra-chave como uma chave de hash, ela simplesmente retorna o valor de hash pré-calculado. Para seqüências de caracteres e símbolos, o hash é recalculado em todas as pesquisas.

O motivo pelo qual as mesmas palavras-chave nomeadas são sempre idênticas, elas contêm seus próprios valores de hash. Como a pesquisa em mapas e conjuntos é feita a partir de chaves de hash, isso envolve uma melhor eficiência de pesquisa no caso de várias pesquisas, não na pesquisa em si.

Ivan Pierre
fonte
0

Palavras-chave são globais , símbolos não são .

Este exemplo está escrito em JavaScript, mas espero que ajude a transmitir o ponto.

const foo = Symbol.for(":foo") // this will create a keyword
const foo2 = Symbol.for(":foo") // this will return the same keyword
const foo3 = Symbol(":foo") // this will create a new symbol
foo === foo2 // true
foo2 === foo3 // false

Quando você constrói um símbolo usando a Symbolfunção, obtém um símbolo distinto / privado toda vez. Ao solicitar um símbolo por meio da Symbol.forfunção, você receberá o mesmo símbolo sempre.

(println :foo) ; Clojure
System.out.println(RT.keyword(null, "foo")) // Java
console.log(System.for(":foo")) // JavaScript

Estes são todos iguais.


Os nomes dos argumentos das funções são locais. ou seja, não palavras-chave.

(def foo (fn [x] (println x))) ; x is a symbol
(def bar (fn [x] (println x))) ; not the same x (different symbol)
John Leidegren
fonte