- O ponto central de Lisp não é a sintaxe com parênteses, mas a mentalidade de estender a linguagem para adequá-la ao problema; seu real valor aparece quando se aprende também REPL, pacotes, símbolos, condições e reinicializações
- Graças à homoiconicidade, em que código e dados são ambos representados como listas, macros podem tratar código antes da avaliação como se fosse dado, criando novas estruturas de controle e abstrações sintáticas
- Mesmo o
while, ausente em Common Lisp, pode ser adicionado com defmacro, mas se for imitado com uma função, os argumentos são avaliados imediatamente e o body vira um valor, não código
- O desenvolvimento em Lisp é mais próximo de um desenvolvimento guiado por REPL, em que o código é avaliado continuamente em um processo em execução, permitindo redefinir funções, macros e variáveis e evoluir o programa sem interrompê-lo
- Quando a extensibilidade da linguagem se combina a um sistema vivo, é possível criar software extensível que expõe DSLs internas aos usuários; AutoLISP e Emacs são exemplos representativos
Lisp exige uma sensibilidade de programação diferente
- Programadores que entram em contato com Lisp pela primeira vez estranham a sintaxe cheia de parênteses, a indentação peculiar e a forma como
format recebe a saída padrão como primeiro argumento
- Para aprender Lisp, é preciso ir além da leitura de código e lidar também com pacotes e símbolos, criação de projetos, importação de bibliotecas, REPL, condições e reinicializações
- A mudança maior aparece na forma de compor algoritmos
- Lisp torna possíveis coisas difíceis de fazer em outras linguagens e também muda o formato dos algoritmos
- O fluxo passa a ser primeiro fazer a linguagem crescer de acordo com o problema e, depois, escrever o programa nessa linguagem
- O paradoxo Blub é um conceito que explica por que programadores que só usaram linguagens menos poderosas têm dificuldade para perceber os pontos fortes de Lisp
Linguagem extensível
- Lisp pode estender a si mesma, e especialistas em Lisp a chamam de programmable programming language
- A ferramenta central é
macro
- Não se limita a eliminar código repetitivo, como macros em C, Rust e Swift
- Macros de Lisp podem criar novos componentes que se tornam parte da linguagem
- Common Lisp não tem um operador
while padrão, mas é possível adicioná-lo diretamente com defmacro
(defmacro while (condition &body body)
`(loop while ,condition do
(progn ,@body)))
- Essa macro
while executa várias instruções de body enquanto condition for verdadeira
loop é uma macro para escrever iterações complexas
progn executa várias expressões em sequência e retorna o resultado da última expressão
- Como resultado, é possível usar a forma
(while ...) em vez de (loop while ... do (progn ...)), deixando o código mais curto e com uma estrutura parecida com o while de C
A diferença decisiva entre macros e funções
- Se tentarmos criar o mesmo comportamento como uma função
fake-while, ela falha
(defun fake-while (condition body)
(loop while condition do
(funcall body)))
- Na chamada de
fake-while, os argumentos são avaliados primeiro
condition se torna o valor verdadeiro t
(print counter) dentro de progn é executado e (decf counter) retorna 2
body se torna o valor 2, não um bloco de código
- Depois disso,
funcall espera uma função, mas recebe 2, então ocorre um erro de tipo como The value 2 is not of type FUNCTION
- Já a macro
while não avalia condition e body imediatamente; ela os preserva
- É possível verificar o resultado da expansão com
macroexpand-1
- O compilador recebe o código na forma expandida
(LOOP WHILE ... DO (PROGN ...))
- Ao contrário de funções, macros não avaliam seus argumentos antecipadamente e os tratam como dados puros, o que torna essa transformação possível
Listas, s-expression e homoiconicidade
- Programas em Lisp são compostos por uma sequência de symbolic expressions, ou s-expressions
- Uma s-expression se divide em dois tipos
- Átomo (atom): unidade de dados como número, string ou símbolo
- Lista (list): coleção que contém átomos ou outras listas
- O nome Lisp vem de LISt Processing, e as instruções que compõem um programa também são representadas como listas
- Em Lisp, listas são tanto a principal estrutura de dados quanto a forma de escrever código
- A propriedade de código e dados serem ambos representados como listas é chamada de homoiconicidade (homoiconicity)
- A mesma lista
(+ 1 2) se comporta de formas diferentes dependendo de ser avaliada ou não
(+ 1 2) é avaliada como código e retorna 3
'(+ 1 2) não é avaliada e retorna a lista de dados como está
- Lisp usa notação polonesa, colocando o nome da função como primeiro elemento da lista e os argumentos depois
- Como a fronteira entre código e dados é fina, macros podem transformar código-fonte e criar programas que escrevem programas
Abstração de código criada por macros
- Ao estender a linguagem, é possível criar novos componentes mais expressivos para uma área específica do programa
- Boilerplate repetitivo pode ser substituído por macros customizadas, reduzindo código e economizando tempo
- É possível criar novas estruturas de controle para controlar o acesso a recursos e a avaliação de forms
- Macros geram código, melhoram desempenho e oferecem abstração sintática que esconde código complexo e propenso a erros
Lisp é um sistema vivo
- Lisp é tratado menos como uma simples linguagem de programação e mais como um sistema vivo em execução
- Em linguagens comuns, o fluxo geralmente é escrever código no editor, compilar, executar e então observar, testar e depurar
- Em Lisp, primeiro se inicia um processo Lisp, conecta-se ao REPL e carrega-se o projeto dentro desse processo
- REPL é a sigla de Read-Eval-Print Loop, um ambiente interativo que avalia código e mostra imediatamente o resultado
- Ele funciona como uma janela para observar o processo Lisp que está executando o programa atual
- Desenvolvedores Lisp continuam avaliando código dentro do processo em execução e verificam os resultados diretamente no REPL
- Testes de funções individuais
- Consultas a banco de dados
- Inspeção de variáveis
- Tarefas como depuração também podem ser feitas no REPL
- O processo Lisp não precisa parar e pode permanecer vivo por semanas
- Funções, macros e variáveis continuam sendo definidas e redefinidas no ambiente interno, chamado environment; esse fluxo é chamado de desenvolvimento guiado por REPL
Hot reloading em Lisp
- No frontend web, é comum a experiência de código JavaScript sendo hot reloaded ao salvar arquivos ou atualizar a página
- O hot reloading comum depende de ferramentas e técnicas separadas, como monitoramento de arquivos, recompilação dos módulos alterados e injeção de mudanças via WebSocket
- Nem todas as stacks de software oferecem hot reloading no mesmo nível
- Alguns frameworks de backend exigem recompilação
- Ambientes de desenvolvimento desktop e mobile têm situações variadas
- Linguagens de baixo nível exigem compilação completa a cada vez
- Em Lisp, hot reloading não é uma ferramenta separada, mas algo que surge naturalmente ao avaliar código no ambiente vivo
- Ao redefinir símbolos, funções, dados e macros passam a usar a nova definição
- Diminui a necessidade de parar e compilar, executar testes separadamente ou usar um depurador especial
- Programar em Lisp é mais próximo de evoluir um programa do que simplesmente montá-lo
Software extensível
- A extensibilidade da linguagem e o sistema vivo facilitam a criação de software extensível em Lisp
- Programas desktop comuns são estendidos por meio de plugins ou linguagens de scripting
- O desenvolvedor precisa projetar e manter o sistema de extensões
- O usuário precisa aprender uma API específica para escrever plugins ou extensões
- Em Lisp, ao encapsular comportamentos com macros e torná-los fáceis de reutilizar, naturalmente se acaba escrevendo uma DSL
- Para tornar um software extensível, basta permitir que usuários usem a DSL criada internamente
- No exemplo de um servidor CMS, é possível expor aos usuários uma macro
html para geração de páginas web server-side
- O usuário pode usar variáveis Lisp, laços
dolist e formatação de strings com format exatamente como são
- Não é necessário aprender uma sintaxe separada como
{{ user_name }} ou {% for %}, típica de linguagens de template tradicionais
- Essa DSL herda diretamente as capacidades de condicionais, recursão, funções de ordem superior e depuração passo a passo pelo REPL de Lisp
- No exemplo de um software de gráficos matemáticos, é possível expor uma DSL para fórmulas e desenho, permitindo que o usuário desenhe curvas e pontos com pouco código
Casos reais e a posição de Lisp
- O AutoCAD usa AutoLISP para automatizar tarefas repetitivas e gerar geometrias complexas
- Emacs é um editor de texto implementado em grande parte em seu próprio dialeto de Lisp, garantindo alta extensibilidade
- Leitor de PDF
- Navegador web
- Cliente de e-mail
- Leitor de RSS
- Multiplexador de terminal
- Cliente Git
- Player de música
- Cliente de chat
- Planilha
- Cliente IRC
- São listados até casos de extensão para gerenciador de janelas de desktop
- R. M. Stallman avalia Lisp como uma linguagem que permite compreender o significado de uma linguagem de programação poderosa e elegante
- A expectativa de que Lisp um dia fosse amplamente usada como linguagem padrão não se concretizou, e parece improvável que isso aconteça no futuro
- Ainda assim, Lisp sobrevive desde a década de 1960 e se tornou a linguagem de programação em uso ativo mais antiga depois de Fortran
- O valor de Lisp não vem de um recurso individual como extensibilidade, ambiente interativo ou REPL, mas da combinação deles
1 comentários
Opiniões do Hacker News
A programação existe sobre uma tensão entre o lado luminoso e o lado sombrio
O lado luminoso tenta impedir que o programador cometa erros: elimina
goto, adiciona tipagem estática e torna bugs impossíveis de expressarO lado sombrio dá poder ao programador: libera macros, sobrecarga de operadores, código auto modificável e até regex de várias linhas à vontade
É interessante que Lisp seja claramente do lado sombrio, no sentido de que o programador pode fazer qualquer coisa, e ainda assim seja respeitada também pelos programadores do lado luminoso. Talvez seja porque a simplicidade da linguagem a faz parecer platônica e quase incapaz de se corromper, ou talvez porque Lisp seja tão pura que abranja os dois lados, como um deus que criou o universo da programação
Você não pode escolher com quem vai trabalhar, nem o nível de habilidade dentro da equipe. Quando colegas menos experientes cometem erros, quanto mais permissiva for a linguagem, maiores podem ser as consequências
É por isso que revisão de código é necessária, mas aí você transforma programadores experientes em professores. Parte do tempo gasto elevando o nível de outros programadores é desperdiçado porque programadores entram e saem o tempo todo. A IA pode mudar essa dinâmica
No fim, o ponto central é manter equipes pequenas e altamente qualificadas, mas isso não é fácil por causa da política corporativa. Por exemplo, muitas vezes se sugere adicionar mais desenvolvedores por causa do fator ônibus ou para encurtar o prazo de lançamento
Sistemas de alta confiabilidade também são escritos em Erlang, que, se você semicerrar os olhos, pode ser visto como outro dialeto de Lisp. Existe até o LFE, uma versão baseada em S-expressions, um Erlang com cara de Lisp
O ponto central da confiabilidade de Erlang não é um nível excepcional de prevenção de erros, e sim a recuperação de erros. Gosto dessa classificação entre luz e trevas
Mesmo sem tipagem estática e com macros que podem virar bagunça, a linha de base do pensamento declarativo e funcional é muito mais forte, então o ponto de partida para pensar e raciocinar sobre programas é melhor e mais claro
Essa divisão entre luz e trevas parece simplificar demais. O equilíbrio das linguagens de programação é um tema muito complexo e interessante
Depois de experimentar várias linguagens por anos, no fim tudo dependia do contexto de uso, do gosto pessoal e dos objetivos. Não existe “a melhor linguagem de programação de todos os tempos”, e também não existe “a melhor para programação do lado luminoso” ou “a melhor para programação do lado sombrio”
Na pintura artística também não existe algo como lado luminoso ou sombrio. Certamente há quadros maiores que outros, mas não existe “o melhor quadro” que todo mundo ache o mais belo em comparação com todos os demais
https://en.wikipedia.org/wiki/Malbolge
https://en.wikipedia.org/wiki/Clean_(programming_language)
https://en.wikipedia.org/wiki/K_(programming_language)
Nos últimos meses surgiram novos editores e ferramentas excelentes, então não vale deixar passar
Mine é um app de download único que oferece tudo o que você precisa para experimentar um fluxo de desenvolvimento interativo e incremental, incluindo hot reloading e depuração instantânea. É para CL e Coalton
https://coalton-lang.github.io/20260424-mine/
OLIVE é um plugin artesanal para VSCode, e ICL é um novo REPL para terminal e navegador com recursos avançados. Como bônus, também há um kernel JupyterLite baseado em JSCL, então ele roda 100% no navegador
Tudo pode ser visto aqui: https://lispcookbook.github.io/cl-cookbook/editor-support.ht...
mine. Tem algum link?Parece que o site está com um bug de syntax highlighting. Os trechos de código incluídos no texto principal aparecem em preto, e ao selecionar com o mouse dá para ver o texto de verdade
Vejo o mesmo bug no Chrome de desktop e no Safari no iPad
Uma solução alternativa é abrir um dos elementos de código no depurador do navegador e adicionar
color: whiteao estilo:not(pre) > codeHá muitos textos exaltando as vantagens de Lisp. Eu também gostaria de ver textos que critiquem com calma Lisp, suas ideias e seu lugar no ecossistema de linguagens
No fim, esses textos e os artigos do PG referenciados aqui acabam ficando perto de “quem sabe, sabe”. Entendo o apelo e também entendo as afirmações explícitas e implícitas que este texto faz
Programação de computadores amadureceu bastante nos últimos 60 anos. Gostaria de ver mais textos com análises mais bem refletidas
O segundo defeito é que ela consome anos do tempo de pessoas suficientemente competentes, mas o resultado não justifica esse tempo investido. Algo como Python também basta. Acho que teria sido melhor usar a maior parte do tempo que investi em Lisp em outra coisa
Clojure, ClojureScript, Clojure-Dart, Fennel, Jade, Jank, Jolt e Coalton são linguagens relativamente recentes e ainda estão evoluindo. Só de cabeça lembro dessas, e há muito mais
Em certo sentido, Lisp não é uma linguagem de programação, mas uma ideia. Ela influenciou quase toda linguagem de programação que usamos hoje e continua influenciando. É difícil criticar uma ideia “com calma”; é parecido com criticar teoria dos grupos. O que dá para discutir são os prós e contras de implementações específicas dessa ideia
async/awaitpadronizado nem um modelo de concorrência padronizado. O padrão não é atualizado desde 1995, então isso provavelmente nunca vai acontecerPara algumas pessoas, isso é mentalmente atraente. Dá vontade de comparar com um gênero musical realmente de nicho. Poucas pessoas gostam, mas quem gosta, gosta com muita intensidade. É como Stockhausen da programação
No fundo é um fandom. Um fandom surpreendentemente duradouro, mas que nunca rompeu para o grande público e provavelmente não vai romper. Agora a posição é ainda pior. Se você está armado com LLMs e não se importa tanto assim com o código em si, por que mandaria escrever em Lisp?
Faço Lisp há tempo demais e acabo não valorizando adequadamente essas funcionalidades. Aí, quando vejo com choque e horror as pessoas sabotando a si mesmas em linguagens populares e economicamente menos arriscadas, de repente volto a sentir o valor de Lisp
Em ambiente comercial, linguagens específicas de domínio são um antipadrão. Alguém cria uma linguagem específica de domínio mal documentada que só ele entende e depois vai embora
Os programadores que vêm depois precisam se esforçar para decifrar essa linguagem estranha. Quase sempre é melhor usar estruturas e recursos da linguagem padrão. Código é lido mais vezes do que escrito
Na prática, o que você provavelmente rejeita é a falta de transparência referencial. Para ser justo, isso é um problema em muitas linguagens, inclusive Lisp
Um bom exemplo é o próprio macro
LOOPde Common Lisp. Se o uso que alguém fez for difícil de entender, você pode pedir ao Lisp para expandi-lo em chamadas primitivas mais verbosas semLOOP, e não precisa entenderLOOPde forma alguma. Na prática, dá até para substituir o formLOOPpelo código expandidoEssa é uma diferença fundamental em relação à maioria das outras linguagens, nas quais o código de linguagem específica de domínio muitas vezes é, na prática, uma estrutura de dados interpretada
Há coisas realmente poderosas e únicas nos Lisps, mas eu preferia que esses textos não continuassem incluindo REPL e hot reloading
REPL já era requisito básico em linguagens interpretadas, e até em algumas compiladas, desde muito tempo atrás. Hot reloading não é algo único, nem particularmente amplamente usado. Como é preciso lidar com estado e patches, existe um motivo para redefinir tudo inteiro ser considerado boa prática quando se quer facilitar o raciocínio
Isso permite um desenvolvimento muito mais interativo do que em outras linguagens interpretadas
Claro, não é perfeito. Mas funciona muito bem para o tipo de mudança que você faz ao iterar sobre a experiência do usuário
Ainda assim, vale destacar que boa parte dos aspectos avançados de hot reloading já foi tratada em Common Lisp. O mesmo vale para o fato de que o REPL costuma ser usado menos como lugar para digitar diretamente e mais como uma interface muito poderosa entre a imagem em execução e as ferramentas
Mesmo assim, concordo que só o fato de essas coisas existirem não as torna tão especiais hoje em dia
O que fazer se uma definição de classe é substituída por um reload, mas as instâncias existentes continuam lá? Dialetos de Common Lisp têm respostas úteis para esse tipo de pergunta, mas nem todo Lisp que você encontrar necessariamente tem
Bash também suporta hot reloading. Já desenvolvi módulos atualizados no próprio lugar assim, usando
source$ . /path/to/script.shSe for uma arquitetura estilo array structure ou uma correção de erro lógico em runtime, normalmente não é nada demais
A utilidade é limitada, mas, se você parte da perspectiva de que vai usar isso bastante, essa limitação começa a desaparecer bem rápido
Pessoalmente, já passei dessa fase. Já usei Common Lisp, Forth e Haskell, e li On Lisp e Let Over Lambda com prazer
Hoje acho que a melhor linguagem de programação é o Triage Calculus do Barry Jay. É mais próxima da lógica combinatória ou do cálculo lambda sem tipos
Mas, diferente do cálculo lambda, o Triage Calculus tem citação embutida e introspecção parecidas com
CAReCDRdo Lisp, então é fácil adicionar verificação de tipos. Por isso, no TC, se você conseguir criar a abstração certa, pode ter qualquer sintaxe que quiser. É realmente a linguagem de programação definitivaO TC mostra que a distinção entre, de um lado, recursos e sintaxe da linguagem de programação e, de outro, definições de funções/API da biblioteca padrão ou do código do usuário é uma falsa dicotomia. Sempre que você escreve código pensado para reutilização, está adicionando algo à linguagem. Tudo isso pode ser expresso como algum termo do TC
Toda discussão sobre sintaxe é uma questão de hábito. Dito isso, o único recurso de sintaxe que eu realmente queria no TC é a abstração
let over lambda, porque organizar combinadores manualmente é um pouco incômodoTexto bem escrito
Antigamente eu achava que um dia todo mundo usaria Lisp e, quando tivéssemos ótimas ferramentas e bibliotecas, tudo ficaria maravilhoso. Na verdade, meu plano para a aposentadoria era criar bibliotecas de alta qualidade para linguagens Lisp para ajudar a acelerar esse processo
A ascensão da IA será o fim desse sonho? Será que, mais uma vez, resolvemos o problema só acrescentando mais tralha? Em vez de uma IA superinteligente escrever código na melhor linguagem de programação possível, será que vamos simplesmente despejar um monte de código Python e insistir até funcionar?
Não sei se isso importa. Eu só queria um mundo com elegância
“Jean-Marie Hullot criou o ‘SOS Interface’ para o Macintosh enquanto trabalhava no INRIA, escrito em Lisp, e este foi o primeiro ‘interface builder’ moderno”
https://denninginstitute.com/itcore/userinterface/GUIHistory...
Fico imaginando como teria sido se isso tivesse virado um produto Mac dominante, em vez de ir para a NeXT e ser usado com Objective-C
LISP combinava bem comigo. Na disciplina de linguagens comparadas na faculdade, fui a única pessoa que fez todos os exercícios de LISP, e aprender LISP também me ajudou bastante a usar TeX
O que eu queria era um toolkit GUI nativo ou multiplataforma decente e open source, além de uma forma fácil de distribuir projetos como código compilado executável independente
Seres humanos conseguem expressar boas ideias em ambas. É melhor pensar na linguagem como uma ferramenta. Uma furadeira de impacto não é superior a uma furadeira rotativa simples. Para construir um deck, a furadeira de impacto pode ser mais adequada, mas as duas dão conta do recado
Achei que este fosse https://web.archive.org/web/20120106121645/http://wiki.alu.o...
Isso me trouxe lembranças de acompanhar comp.lang.lisp. Era quase um drama. Havia não só magia da programação, mas também muitas figuras marcantes e acontecimentos