- A visão de culpar os símbolos formais pela dificuldade da programação gera a expectativa equivocada de que, se a máquina entender linguagem natural, a carga humana diminuirá
- O risco das primeiras linguagens de máquina foi parcialmente amenizado por linguagens de programação de alto nível, mas a essência permaneceu: respostas erradas apenas viraram mensagens de erro, e instruções precisas continuam sendo necessárias
- Interfaces em linguagem natural não são uma solução de divisão de trabalho; elas podem aumentar o custo de cooperação e comunicação entre humanos e máquinas, elevando a carga para ambos os lados
- O desenvolvimento da matemática mostra que sistemas de símbolos formais criados por figuras como Vieta, Descartes, Leibniz e Boole foram ferramentas centrais para lidar com raciocínios complexos
- Se a programação em linguagem natural tivesse sido adotada como entrada e saída básica, a ciência da computação provavelmente teria acabado sendo um longo desvio até retornar a um sistema formal utilizável
Expectativas e equívocos em torno da programação em linguagem natural
- Desde os primórdios do cálculo automático, algumas pessoas viam como defeito o fato de a programação exigir atenção e precisão demandadas por símbolos formais
- Consideravam problemático que a máquina executasse rigidamente até comandos errados, e esperavam uma máquina mais “sensata” que rejeitasse erros administrativos triviais
- A linguagem de máquina tinha pouquíssima redundância, sendo uma interface perigosa entre humano e máquina
- Em resposta, foram desenvolvidas linguagens de programação de alto nível
- Com o tempo, surgiu a melhoria pela qual muitos erros triviais passaram a resultar em mensagens de erro, em vez de respostas incorretas
- Ainda assim, a máquina abstrata correspondente à linguagem de programação continua sendo um autômato que executa fielmente os comandos dados e pode até executar comandos sem sentido
- A proposta de instruir a máquina em linguagem natural se apoia na lógica de que, mesmo tornando a máquina mais complexa, isso poderia reduzir a carga humana
- Essa lógica só parece plausível quando se vê a “obrigação de usar símbolos formais” como a causa da dificuldade
- Mudar a interface não é simplesmente redistribuir trabalho; isso adiciona custos de cooperação e comunicação através da interface
- Empiricamente, mudar a interface pode aumentar bastante a carga de trabalho dos dois lados, e por isso cresce a preferência por uma “interface estreita”
Como os símbolos formais expandem o pensamento
- Na história da matemática, abordagens centradas em linguagem natural ou em figuras repetidamente revelaram seus limites
- A matemática grega permaneceu presa a atividades linguísticas e geométricas, entrando em estagnação
- A “algebra” muçulmana ensaiou por um momento o uso de símbolos, mas desapareceu ao voltar ao estilo retórico
- A Europa Ocidental se afastou das tentativas de precisão linguística do escolasticismo medieval graças a símbolos formais conscientemente projetados por figuras como Vieta, Descartes, Leibniz e, depois, Boole
- A vantagem do texto formal está em que manipulações válidas só precisam satisfazer algumas regras simples
- Essa regularidade se torna uma ferramenta para excluir vários tipos de falta de sentido difíceis de evitar na linguagem natural
- O uso de símbolos formais não é um fardo, mas quase um privilégio
- Graças aos símbolos formais, estudantes podem aprender coisas que antes só gênios conseguiam fazer
- A frase, no prefácio de um relatório técnico de 1977, de que “por clareza, evitamos até mesmo os símbolos padrão dos conectivos lógicos” mostra que esse mal-entendido não se limita a uma única pessoa
- A “naturalidade” da linguagem natural leva ao fato de que é fácil produzir frases cujo sem sentido não é evidente
Ciência da computação em um mundo onde só a linguagem natural é permitida
- Se desde o início a entrada e saída dos equipamentos de processamento de informação tivessem sido feitas apenas na língua materna, a ciência da computação teria sido algo próximo de uma “black art” em busca de migrar para um sistema formal suficientemente definido
- Seria necessária a inteligência do mundo inteiro para estreitar a interface até um nível utilizável
- Considerando a história da humanidade, isso poderia ter levado mais alguns milhares de anos
- Soma-se a isso a preocupação de que o rumo da educação no Ocidente, ao se afastar do treinamento intelectual, reduziu fortemente a capacidade das pessoas de lidar com a própria língua
- Cita-se como exemplo que, em artigos científicos, relatórios técnicos e publicações governamentais, há muitas palavras sem sentido quando se lê com atenção
- Esse fenômeno é chamado de “The New Illiteracy” e serve de alerta até para defensores que não têm a percepção técnica necessária para prever o fracasso da programação em linguagem natural
- A conclusão é marcada pela suspeita de que máquinas programadas em linguagem natural seriam tão difíceis de usar quanto de construir, seja em Dutch, English, American, French, German ou Swahili
1 comentários
Comentários do Hacker News
Tudo bem defender LLMs aqui, mas me pergunto como seria fazer o inverso. Pegar um projeto de complexidade média e usar seu LLM favorito para converter o código de volta para linguagem natural.
Ele explicaria os comportamentos e requisitos contidos no código-fonte de forma razoável, sem perder detalhes suficientes para reproduzir o programa? Essa explicação em linguagem natural seria mais fácil de raciocinar?
Acho que há um motivo para os apps de vibe coding que as pessoas mostram serem, em geral, simples. Existe um nível em que fica difícil gerenciar complexidade e precisão; ainda que se consiga definir em inglês comum, resta saber se essa descrição é mais explicativa do que uma linguagem escalável, compreensível e precisa.
Também acho que o motivo de documentos jurídicos não serem escritos em inglês simples vai além de simplesmente criar barreiras de entrada.
METAR YSSY 031000Z 08005KT CAVOK 22/13 Q1012 RMK RF00.0/000.0.Pilotos novos quase sempre perguntam “por que não escrever em palavras?”, e, na prática, a maioria dos apps de planejamento de voo transforma esse código em prosa.
Mas pilotos profissionais e controladores preferem muito mais o formato codificado. Por ser uma única linha, é compacto; o formato é bem definido, então você sabe exatamente onde encontrar o item de que precisa; e é claro, sem ambiguidade.
Com matemática e programação é igual: quando se atinge certo nível de proficiência, a complexidade e a redundância da linguagem natural custam mais do que beneficiam. Parece se aplicar a todas as áreas especializadas.
Recuperar informações na prosa toma muito tempo, e pessoas lendo textos longos começam a sublinhar, fazer anotações e criar suas próprias abreviações.
Formatos compactados e abstrações reduzem a carga sobre a memória de trabalho e a busca por informação. Então talvez não seja necessariamente apenas um problema de precisão da linguagem.
Pode parecer que, para ir dessa frase até um app funcionando de fato, seriam necessários inúmeros detalhes de implementação, mas só com esse nível de informação já há uma chance de chegar a uma aplicação funcional que resolva minha necessidade.
E, se for possível criar o suficiente com isso, pedidos como “você pode mudar para azul-centáurea?” também ficam fáceis, e o usuário pode iterar a partir daí.
Se você der a uma LLM apenas uma ISA e um driver de vídeo e pedir para ela criar um app gráfico em assembly, não vai obter nada.
Mas, se houver montanhas de abstrações empilhadas, provavelmente passa a ser possível.
Não estou tentando defender LLMs; só acho que, ao fornecer as abstrações corretas e componentes reutilizáveis, dá para chegar muito mais perto.
Isso me lembra uma citação antiga de Hal Abelson:
“Por trás da nossa abordagem a este assunto está a convicção de que ‘ciência da computação’ não é uma ciência e que sua importância tem pouco a ver com computadores. A revolução dos computadores é uma revolução na forma como pensamos e na forma como expressamos o que pensamos. A essência dessa mudança é o surgimento de algo que talvez seja mais bem chamado de epistemologia procedural. Trata-se do estudo da estrutura do conhecimento de um ponto de vista imperativo, em contraste com o ponto de vista mais declarativo adotado pelos campos clássicos da matemática. A matemática fornece uma estrutura para lidar precisamente com a noção de ‘o que é’. A computação fornece uma estrutura para lidar precisamente com a noção de ‘como fazer’.”
Por mais que existam demos impressionantes e declarações de que “a programação morreu por causa da IA”, grande parte do trabalho real se desloca para pré-processamento, pós-processamento e avaliação em torno da IA.
É bom por aumentar a acessibilidade da programação, mas não consegue realmente substituí-la.
Finalmente alguém expressou isso desse jeito. A linguagem natural tem limites inerentes, decorrentes das limitações mentais humanas. A mente humana às vezes pensa de forma abstrata demais ou concreta demais, e deixa passar detalhes importantes ou generalizações.
Pelo que sinto diretamente como programador, os problemas — ou até os absurdos — de uma tarefa muitas vezes só aparecem depois que começo a implementá-la como código, isto é, em um sistema simbólico rigoroso.
Além disso, muitas vezes o tempo necessário para explicar algo com precisão em linguagem natural é maior do que simplesmente escrever o algoritmo em código.
Com que frequência reescrevemos uma frase, dizemos “na verdade, o que eu queria dizer era...” ou reformulamos um e-mail antes de enviar? Somos humanos, e raramente acertamos de primeira.
Agora estamos convertendo essa forma imperfeita de comunicação, a linguagem natural, em código — a linguagem de máquinas notórias por executar o que foi dito, não o que se pretendia.
Processamento de linguagem natural é extremamente útil para colocar a criação de apps ou scripts no caminho certo desde o início. Mas, no fim, pode ser necessário refatorar várias partes.
Você não precisa ser um mestre em código para extrair valor de LLMs, mas saber programar ainda ajuda e, às vezes, é necessário.
/s: É porque ainda não fomos longe o bastante. As pessoas criam programas de computador em linguagem natural, mas, em vez disso, deveriam executar o prompt diretamente
“Você é um sistema gráfico. Você é a entidade que gerencia o que há na tela. Pode receber de todos os programas pedidos para criar e destruir ‘janelas’, e também pedidos adicionais para desenhar texto, linhas, círculos etc. em janelas criadas anteriormente. Os itens podem ser de qualquer cor.
Além disso, você deve enviar mais informações de clique para quem criou a janela em que o usuário clicou com o mouse.
O gerenciador de janelas é um programa especial e pode lhe informar onde quais janelas são exibidas em todos os monitores conectados ao sistema”
E “Você é um programa de jogo da velha. Há um sistema gráfico que gerencia o que há na tela. Você pode mandar esse sistema criar e destruir ‘janelas’, e pode pedir que ele desenhe texto, linhas, círculos etc. em janelas criadas anteriormente. Os itens podem ser de qualquer cor.
Os gráficos que você desenha devem mostrar uma partida de jogo da velha em que o usuário joga seu turno clicando com o mouse. Se o usuário vencer…
Adicione anúncios ao jogo, a menos que o usuário tenha uma assinatura com cobrança por clique”
Isso deve ser suficiente para o jogo rodar
Para salvar, será preciso outro prompt. “Você é um sistema de arquivos. Você é a entidade que persiste dados em disco…”
E também será necessário “Você é um sistema operacional multitarefa. Você dá a vários LLMs a sensação de que têm controle total da CPU e da memória do sistema. Você…”
Espero ver isso no início de abril do ano que vem
“A linguagem de máquina praticamente não tinha redundância de nenhuma forma e logo foi reconhecida como uma interface desnecessariamente perigosa entre humanos e máquinas. Em parte como resposta a essa percepção, foram desenvolvidas as chamadas ‘linguagens de programação de alto nível’ e, com o tempo, aprendemos a aumentar em certa medida a proteção contra erros bobos. Foi uma melhoria importante o fato de que agora muitos erros bobos resultam em mensagens de erro em vez de respostas erradas.”
Tenho a sensação de que nós, coletivamente, mergulhamos rápido demais na programação com LLMs. Gostei muito de como Rust evoluiu no sentido de apontar erros bobos e tornar muito mais claro como corrigi-los
Como desenvolvedor, ainda tenho o contexto e o entendimento do código em que estou trabalhando, e o compilador me informa erros óbvios e como corrigi-los. Já o uso de LLM parece um jogo de adivinhação seminteligente
O compilador do Rust é um mestre ensinando um aprendiz; o LLM parece um graduado confiante corrigindo o mestre. Prefiro muito mais a abordagem do Rust e gostaria que ela avançasse ainda mais, se possível
A linguagem natural é um meio pobre para transmitir regras e comandos. A situação atual dos EUA é um bom exemplo
Ainda estamos discutindo o que significam certas leis e emendas constitucionais. O significado das palavras muda com o tempo, e o contexto histórico também se torna escasso
Seria bom poder operar máquinas em linguagem natural, mas, como alguém que programa desde meados dos anos 80, acho que a rigidez das linguagens de computador, de BASIC a Go, cria um bom equilíbrio. Ela faz com que quem dá os comandos assuma responsabilidade suficiente para expressar exatamente o que a máquina deve fazer
Discordo em certa medida dessa afirmação. Em empresas reais, a ideia de uma nova funcionalidade muitas vezes começa na cabeça de alguma pessoa da área de negócios. Essa pessoa não vai falar nenhuma linguagem formal
Portanto, seja como for, para implementar a funcionalidade é necessária uma tradução de linguagem natural para linguagem de máquina
Normalmente, a primeira etapa, a tradução de linguagem natural para linguagem formal, fica a cargo de analistas de negócios e programadores. Então por que não receber ajuda do computador nesse processo?
Portanto, ele está refutando não só a ideia de que programas devam ser especificados em linguagem natural, mas também a ideia de que, se removermos a necessidade de entender linguagens formais, aumentaremos nossa capacidade de construir sistemas complexos
Grande parte da “tradução” na verdade não é tradução, mas sim o trabalho de corrigir ambiguidades lógicas, inconsistências e pressupostos equivocados. Se levarmos Dijkstra a sério, muito disso pode ocorrer até dentro da linguagem natural, porque ali estão programadores que passaram a vida formalizando coisas
Há também outras profissões que exigem bastante pensamento formal, como a matemática. Além disso, ao converter provas antigas em provas computacionais, foram encontrados buracos e lacunas em muitas provas amplamente aceitas
Não foram muitas as que acabaram derrubadas, mas ainda não temos nem uma prova completa do último teorema de Fermat https://xenaproject.wordpress.com/2024/12/11/fermats-last-th...
Se você não pensa dentro de um sistema formal, suas ideias pioram. Porque você não trata seus próprios pensamentos como algo formal
Quanto a como traduzir a ideia da “pessoa de negócios” do exemplo, ele provavelmente não teria muito a dizer. Do ponto de vista dele, a ideia dessa pessoa de negócios já é rasa e ruim por não seguir o formalismo, e nem vale a pena ser traduzida
Ao “deixar o computador ajudar no meio”, você logo esbarra no problema de precisar de uma linguagem natural cada vez mais formal para obter da máquina um resultado bom o suficiente
Mesmo que não seja tão formalizada quanto uma linguagem de programação, ela certamente existe
Sempre que você tenta definir qualquer processo, mesmo sem perceber, acaba tendendo à formalização
“Foi uma melhoria importante que muitos erros bobos passassem a resultar em mensagens de erro em vez de respostas erradas. Mesmo essa melhoria não agradou a todos. Algumas pessoas consideravam mensagens de erro impossíveis de ignorar mais irritantes do que resultados incorretos e, ao julgar os méritos relativos de linguagens de programação, ainda parecem equiparar ‘facilidade de programar’ à facilidade de cometer erros que não são detectados.”
Se eu não soubesse quem escreveu isso, pareceria uma cutucada direta em quem odeia Rust
Depois de usar por um tempo Scala, uma linguagem que permite expressar invariantes mais fortes por meio de tipos do que Rust, deixei de ver essa característica como uma vitória clara em qualquer situação. Não acho mais que “tipos mais fortes == necessariamente melhor”
“Não permitir erros” tem um custo. Quando o sistema de tipos é realmente rígido, o trabalho exploratório fica bem mais difícil. Iterações rápidas podem se tornar impossíveis
Uma pequena alteração pode exigir redesenhar metade do programa só para voltar a satisfazer o sistema de tipos
É um trade-off. Como todo o resto. É bom para um produto final robusto, mas atrapalha experimentos rápidos
Alguém explicou bem esse problema no contexto de Rust e desenvolvimento de jogos: https://loglog.games/blog/leaving-rust-gamedev/
Mas não é um problema limitado a Rust ou ao desenvolvimento de jogos
Certos tipos de bobagem parecem atemporais
O que ele está falando aqui são linguagens interpretadas
Ele também era um daqueles matemáticos que hoje seriam chamados de cientistas da computação, cujos “algoritmos” eram basicamente uma reafirmação da matemática e não exigiam um dispositivo. Alguém temperamentalmente hostil à atividade embaraçosa de programar computadores reais
Especificar e criar uma aplicação em linguagem natural é bem parecido com ter um documento de design de jogo antes de começar um protótipo de jogo
Mas, depois que você implementa a maior parte do que queria, a implementação vira a referência, e o GDD geralmente é descartado porque diverge do jogo real
Insistir que, a cada mudança, seja preciso ler o GDD, implementar o recurso e depois sincronizar o GDD de novo é trabalhoso e, na prática, não funciona bem. Nunca vi isso acontecer
Se algum dia IA/LLMs conseguirem programar do zero a próxima versão do Linux ou do Windows usando apenas uma sequência de prompts, todas as premissas mudarão, mas agora claramente ainda não chegamos lá, e não sabemos se chegaremos
A linguagem natural é muito boa para descrever requisitos técnicos de sistemas complexos. Ou seja, é boa para explicar não a implementação atual do código em si, mas por que a implementação atual foi escolhida em vez de outras possíveis
Ela serve para registrar não o que o código faz, mas o que ele deve fazer — em outras palavras, as partes ausentes que ficam em lugares como o Jira, e não no repositório
Além disso, se o sistema inteiro puder ser descrito por regras externas e essas regras puderem ser impostas a toda a base de código, isso também poderá oferecer uma capacidade melhor de refatoração
Temos usado linguagens de programação porque elas são fáceis de usar no contexto de automação e computadores e, francamente, antes dos LLMs esse também era o único jeito
Linguagens de programação dão não ambiguidade em escala local, mas, no momento em que alguém copia e cola uma parte do código, isso deixa de funcionar em escala global
Dá para ter certeza de que aquela parte é um programa correto, respeitando todas as restrições de alto nível que deveria seguir? Se compilar, será um programa que executa, mas a definição de execução é bem frouxa. Em C++, até um programa que destrói toda a memória pode executar