2 pontos por GN⁺ 2025-04-04 | 1 comentários | Compartilhar no WhatsApp
  • 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

 
GN⁺ 2025-04-04
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.

    • Como exemplo de outra área, previsões e avisos meteorológicos da aviação são distribuídos em um formato fortemente abreviado e codificado. Por exemplo, o tempo agora em Sydney, na Austrália, é algo como 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.
    • Acho que é mais uma questão de memória de trabalho do que de precisão. O motivo pelo qual humanos têm dificuldade para entender uma versão em prosa suficientemente grande provavelmente é parecido com o motivo pelo qual LLMs têm dificuldade para lidar com uma versão em prosa grande: a memória de trabalho é limitada.
      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.
    • A linguagem consegue carregar uma quantidade enorme de contexto. Por exemplo, a frase “quero um app de navegação moderno para dirigir e gostaria de poder escolher cruzamentos pelos quais eu jamais quero passar” tem baixa complexidade, mas codifica uma quantidade imensa de informação.
      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í.
    • Claro, nós criamos abstrações com vazamento, e isso também acontece em documentos jurídicos.
      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.
    • Há um motivo para documentos jurídicos não serem escritos em inglês simples. Parte da precisão da linguagem jurídica vem do fato de que o significado de certos termos já foi definido com mais exatidão por jurisprudência.
  • 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’.”

    • O ponto central é que computação é fazer coisas acontecerem. Programar com LLMs acrescenta mais uma camada de abstração, mas não elimina a necessidade de precisão e exatidão sobre “o que acontece”.
      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.
    • O que é ensinado hoje nos cursos de ciência da computação certamente não parece seguir essa direção.
    • Hal Abelson irritando tranquilamente cientistas da computação de programação funcional do mundo inteiro.
  • 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.

    • Exato. Tenho uma tendência a preferir abstrações, então costumo entender as coisas de forma abstrata, mas muitas vezes é extremamente difícil expressar isso em linguagem natural.
    • Precisamos de expectativas realistas sobre os limites das LLMs atuais. Até filosoficamente, a linguagem natural é imperfeita para transmitir ideias entre pessoas, embora essa seja sua principal finalidade.
      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

    • Atualmente, esses prompts são implementados internamente por meio de geração e execução de código Python
  • “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

    • Rust e outras linguagens têm inferência de tipos, enquanto LLMs têm o chamado “raciocínio”. LLMs fingem entender, e essa mentira um dia inevitavelmente cobrará seu preço
  • 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?

    • Computadores podem e devem ajudar nesse processo. Mas o ponto de Dijkstra é que a) uma parte significativa das dificuldades das ideias humanas é descoberta no ato de transformar linguagem natural em linguagem formal, e b) esse ato em si treina nosso eu lógico-formal
      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...
    • Parece que você não entendeu completamente o ponto de Dijkstra. Ele não está dizendo para não usar ferramentas que ajudem na tradução; ele está dizendo que não pensar em símbolos formais prejudica o pensamento
      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
    • A primeira etapa não é da linguagem natural para a linguagem formal, mas sim passar as ideias da cabeça para a linguagem natural. É difícil fazer essa etapa direito o suficiente para que um computador possa transformá-la em algo útil
    • Se fizer isso, você deixa de saber o que o computador está fazendo. O ponto central deste texto é que há valor no próprio processo de escrever ideias de forma formal
      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
    • Cada negócio, cada atividade, não tem sua própria linguagem formal?
      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

    • Rust? Desde quando Rust é o ápice da segurança de tipos estática?
      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
    • Acho que ele teria pensado sinceramente nas pessoas que gostavam do PHP da época do fractal-of-bad-design ou do JavaScript do wat-talk
      Certos tipos de bobagem parecem atemporais
    • Como alguém que não gosta de Rust, o problema são as mensagens de erro que aparecem mesmo quando não há erro. O sistema de tipos de Rust não modela com precisão a RAM, a CPU nem dispositivo algum
      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