Formatação de código LISP
-
23-08-2019 - |
Pergunta
Uma das pessoas que dedicaram um tempo para comentar minha outra pergunta Sobre a sintaxe Clojure/Lisp apontou que eu não havia escrito meu código de amostra da maneira padrão. Então ele teve a gentileza de reescrever o trecho de código e isso é uma grande ajuda. Mas levantou outra questão em minha mente. Por que este seria:
(if (= a something)
(if (= b otherthing)
(foo)))
que é a formatação LISP padrão é preferível a este formulário:
(if (= a something)
(if (= b otherthing)
(foo)
)
)
É assim que eu teria formatado ingenuamente esse código devido ao meu fundo de desenvolvimento C ++. Gostaria de saber se há algum benefício para a última formatação ou é apenas um padrão arraigado (como um teclado QWERTY). Não estou tentando ser argumentativo-é difícil para mim entender por que a primeira forma seria preferível. O segundo formulário me ajuda a ver a estrutura do código mais facilmente.
Solução
Os parênteses finais em linhas extras realmente não ajudam a ver a estrutura do código, porque você pode obter as mesmas informações do nível de indentação. No entanto, o segundo formulário ocupa quase o dobro de linhas, forçando você a rolar com mais frequência ao ler o código.
E se você precisar inspecionar os parênteses aninhados mais de perto, um editor que destaca os parênteses correspondentes o ajudará. Isso também será mais fácil quando o parêntese correspondente não estiver muito longe.
Se as expressões ficarem muito longas e complicadas para serem facilmente lidas, também pode ser um sinal de que você deve extrair parte da funcionalidade para uma função separada.
Outras dicas
A maneira como o código LISP é recuado é como o espaço de branco significativo em Python, exceto que é obviamente opcional. A regra básica é que você coloca itens em uma lista embaixo da outra verticalmente, se não estiverem na mesma linha.
(a (b (c (d e)
(f g))
(h i j))
(k l m n))
Sem nem olhar para os parênteses, você pode ver que (d e)
e (f g)
são parâmetros para c
, (c (d e) (f g))
e (h i j)
são parâmetros para b
, e (b (c (d e) (f g)) (h i j))
e (k l m n)
são parâmetros para a
.
Com o seu exemplo, ele deve ser formatado mais corretamente da seguinte forma:
(if (= a something)
(if (= b otherthing)
(foo)))
^ ^
notice how they line up
Agora que o nível de recuo se torna significativo, você não precisa mais confiar no equilíbrio entre parênteses para obter essas informações e, como é mais compacto colocá -las na mesma linha da declaração de fechamento, é isso que os Lispers fazem. É verdade que não é necessário que o código LISP seja formatado dessa maneira, mas é uma convenção bastante padrão que as pessoas usam e podem confiar.
A resposta simples é que o seu jeito não é a maneira como a beira da Lisp faz as coisas. Ter um formato verdadeiro é sempre uma coisa boa para o código, e a macro Pprint oferece esse formato incorporado ao idioma.
É claro, Porque A macro Pprint existe, não é estritamente necessário que você siga a formatação de código padrão, porque as pessoas podem simplesmente executar seu código através do Pprint e obter o que estão acostumadas. No entanto, como todo mundo usa o Pprint ou o aproxima manualmente, você terá dificuldade em ler o código se não fizer da mesma maneira, e você não terá uma macro fácil que transformará o código em seu preferido formato.
Você pode reformular o código LISP com o pacote sreafctor: Pagina inicial.
Algumas demos:
- Formatando a demonstração de buffer inteiro em clojure. Eu testei em um arquivo de clojure com linhas de 10k e levou cerca de 10 segundos para formatar todo (tempo significativo gasto no recuo, não rearranjo de código).
- Formatando a demonstração de buffer inteiro em Emacs lisp
- Transforme entre uma linha <-> Multiline Demo
Comandos disponíveis:
srefactor-lisp-format-buffer
: formatar buffer inteirosrefactor-lisp-format-defun
: Formatar o atual cursor do Defun está emsrefactor-lisp-format-sexp
: Formate o atual cursor do SEXP.srefactor-lisp-one-line
: Transforme o sexp atual do mesmo nível em uma linha; Com o argumento do prefixo, transforme recursivamente todos os Sexps internos em uma linha.
Os comandos de formatação também são utilizados em Lisp e esquema comum.
Se houver algum problema, envie um relatório de problema e ficarei feliz em corrigi -lo.
When you have 10 parentheses to close, it becomes really clunky.
When I used to program Lisp I left a space between the closing parentheses for opening parentheses on the same line and the rest, to simplify counting, like this:
(if (= a something) (if (= b otherthing) (foo) ))
I guess these days that is no longer needed, as editors are more helpful.