- A sintaxe do JavaScript fica facilmente complexa com parênteses aninhados e callbacks, e até UIs pequenas acabam puxando muitas bibliotecas, causando inchaço
- WebAssembly abre caminho para executar outras linguagens no navegador, mas, como no Pyodide, o custo da conexão assíncrona com o loop de eventos do JavaScript é alto
- Como os recursos do navegador e a memória do WebAssembly são limitados, é preciso uma abordagem de negociação, em vez de tentar substituir o JavaScript
- LispE reúne mais de 450 funções em um único binário WASM de 3.3MB, oferecendo juntos recursos de strings, cálculo, matrizes e expressões regulares
- Com
evaljs e asyncjs, ele aproveita funções JavaScript e o DOM, enquanto reduz o inchaço de código com um único binário auditável no lugar de várias bibliotecas externas
Inchaço do JavaScript e limitações do navegador
- A sintaxe do JavaScript fica facilmente complexa porque parênteses, chaves e colchetes se sobrepõem e é preciso acertar a ordem de fechamento
- É mostrado um exemplo de atualização de valores em vários objetos e de renovação condicional de cache dentro de um callback de
forEach
newNames.forEach((name, i) => {
allAgentContents[name] = contents[i];
agentModes[name] = modes[i];
if (compiled[i]) agentCompiledCache[name] = compiled[i];
agentViewingCompiled[name] = viewing[i];
});
- Para tarefas que uma linguagem de programação básica normalmente incluiria, no JavaScript muitas vezes é preciso baixar muitas bibliotecas
- C ou C++ também exigem
include para trabalhar, mas, no caso das bibliotecas JavaScript, muitas vezes é difícil saber quem implementou e quem faz a manutenção
- Há páginas que parecem carregar “metade da internet” só para mostrar hello em uma janelinha
- A internet depende de JavaScript e, mesmo que isso seja escondido com TypeScript, ele continua sendo o porteiro obrigatório toda vez que uma página é aberta no navegador
- Existia o sonho de que o navegador se tornaria o sistema operacional definitivo, tornando Windows ou Mac OS desnecessários, e o JavaScript foi escolhido como a linguagem para concretizar esse sonho
Relação entre WebAssembly e JavaScript
- WebAssembly é mais próximo de uma máquina virtual com sua própria linguagem de máquina, abrindo a possibilidade de programar de outra forma dentro do navegador
- O Pyodide é uma conquista de engenharia impressionante para executar Python no navegador, mas também expõe o custo de operar dentro do domínio do JavaScript
- O
asyncio do Python e o loop de eventos do JavaScript são dois mundos assíncronos que precisam conversar entre si
- A ponte entre esses dois mundos é frágil, e é preciso lembrar a qual deles cada
await pertence
- Os recursos do navegador são limitados, então é preciso uma forma de pensar parecida com a do início da ciência da computação, analisando cada instrução e estrutura no nível dos bits
- É apresentado como referência o início da programação em 1981 em um computador com exatamente 15772 bytes livres
- A memória de um navegador moderno não é tão limitada quanto a daquele primeiro computador, mas o WebAssembly não pode possuir memória livremente como um programa comum e precisa obter permissão prévia de forma restrita
- A atitude central não é lutar contra o JavaScript, mas negociar com ele
A alternativa proposta pelo LispE
- LispE oferece mais de 450 funções dentro de um único binário
- O tamanho do binário WASM é de 3.3 MB
- Recursos de strings, cálculo, matrizes e processamento de expressões regulares ficam reunidos em um só lugar
- O binário WASM está em binaries/wasm
- Embora seja um interpretador pequeno, ele pode lidar com strings,
Float64Array, inteiros, números reais e arrays de strings como valores de retorno
- O LispE é baseado em Lisp, então possui uma estrutura em que a AST permanece viva
- Se a sintaxe Lisp não agradar, é possível usar uma sintaxe transpilada para uma linguagem difícil de distinguir de Python ou Basic
- É possível modificar a grammar para criar uma linguagem no estilo desejado
- Isso também pode ser feito em grego, e já existe um exemplo em grego
- O LispE coopera com o JavaScript sem enfrentá-lo, aproveitando funções JavaScript e recursos do DOM
Chamadas de JavaScript: evaljs e asyncjs
- Para executar código JavaScript dentro do LispE, é possível usar
evaljs e asyncjs
evaljs executa código JavaScript e retorna um valor
asyncjs conecta funções JavaScript definidas pelo usuário na página e callbacks assíncronos
(setq a (evaljs "10 + 20 + 30")) ; execute some JS code
; call_llm is a user-defined JS function in the page
(asyncjs `call_llm("Implement a piece of code in Python to sort strings");` 'mycallback)
(defun mycallback(theresult) ...)
- O
asyncjs funciona com uma Promise de que retornará quando o trabalho terminar
Reduzindo o inchaço de código
- A citação de Wirth de 1995 leva à conclusão de que computadores mais rápidos e modelos maiores não resolvem o problema, e que o código deve continuar enxuto
- O LispE fornece 450 funções expostas ao navegador em um único binário auditável
- Para implementar cada recurso separadamente, seria preciso carregar bibliotecas como
mathjs para cálculo numérico, lodash para coleções, voca para manipulação de strings e simple-statistics para distribuições estatísticas
- Essa abordagem pode crescer para centenas de MB de código com autores, bugs e cronogramas de manutenção diferentes
- O LispE oferece esses recursos em um único código mantido, e, por ser open source, todo o código pode ser auditado
- Considera-se que o Garbage Collector não destrói o desempenho do código no pior momento
- Ele se comunica com o JavaScript de forma transparente por chamadas simples de API e pode retornar estruturas predefinidas
// floats here is a Float64Array
const floats = callEvalLispEToFloats(0, `(normal_distribution 100)`);
2 comentários
O texto pareceu meio aleatório, então desconfiei da fonte, mas era do Naver mesmo, tipo "aff".
Mas, como era de se esperar, a reação não foi boa... Sinceramente, JavaScript já é algo exagerado, então querer usar Lisp chegando ao ponto de subir até um WASM de 3,3 MB é um overengineering difícil de entender mesmo kkk
Sobre o motivo de ser uma conta do Naver, um desenvolvedor do projeto chamado Claudius deixou um comentário dizendo que trabalha na Naver Labs Europe e que foi publicado porque o Naver aprovou como projeto open source.
Não parece ter muita relação com o Naver em si, acho que são só pessoas que realmente amam Lisp...
Opiniões no Lobste.rs
Fica parecendo que a proposta é “desinchar” o JavaScript adicionando um bloco opaco de WASM de 3,3 MB e mandando escrever o app em Lisp
Só com JavaScript puro e zero dependências extras já dá para fazer bastante coisa antes de chegar sequer a um décimo desse tamanho
Não concordo com esse caso de uso, mas é um projeto de paixão em Lisp interessante, com uma estranheza rara hoje em dia, e gosto do fato de toda a documentação ter frases únicas que claramente parecem escritas por uma pessoa
Sempre estão abertos a sugestões do que vale adicionar à biblioteca padrão
Entre as adições recentes estão união/interseção de conjuntos,
sum,base64e outrasDito isso, quase nunca ouvi pedidos por funções de cálculo, e no caso de strings os pedidos recorrentes costumam ser
.reverseou.titleCase.reversenão tem tantos usos convincentes fora de problemas de brinquedo, e.titleCaseé possível, mas precisa de dados de internacionalização, então a discussão ainda está em andamentoAlém disso, nenhuma das duas existe nesta biblioteca
Acabam sentindo que não vale a pena propor algo porque levaria 3 anos para entrar de fato, e que uma pasta
utils/não é ideal, mas pelo menos dá para criar agoraMeu argumento é menos sobre faltar funções no JavaScript e mais sobre o modelo de distribuição
Mesmo com uma biblioteca padrão cheia, o app médio ainda continua carregando megabytes de dependências transitivas do npm
LispE-as-WASM tem 3,3 MB, cerca de 450 funções documentadas, núcleo em C++, código-fonte público no GitHub, e é um experimento para ver como poderia ser um runtime auditável
Na prática, já montei um harness de agentes em cima disso, e estou executando regras em LispE sob demanda dentro do navegador
O event loop do JavaScript continua sendo excelente
Quando alguém diz que a sintaxe está inflada eu já fico em alerta
Uma sintaxe mínima pode ser muito mais difícil de ler do que uma que usa caracteres diferentes para distinções visuais
O que o LispE oferece como alternativa é isto:
... !?
https://github.com/naver/lispe/wiki/5.3-A-la-APL
O ponto de entrada deste projeto é meio estranho, e a página https://github.com/naver/lispe/wiki/1.-Introduction parece melhor
É um projeto de Lisp nativo que também mira WASM, e tem elementos interessantes que devem agradar quem curte linguagens de programação
Minha primeira impressão foi que eram exemplos de JavaScript bem forçados
Grande parte do ódio ao JavaScript parece vir das incompatibilidades dos navegadores antigos, APIs DOM dolorosas e armadilhas de sintaxe, e isso na prática quase não afeta meu dia a dia hoje
O JavaScript moderno, especialmente com TypeScript e regras de lint razoáveis, é bom o suficiente como linguagem
Ainda existem problemas como CJS vs ESM, risco na cadeia de suprimentos e volatilidade do ecossistema, mas a maior parte disso está fora da linguagem em si
Aquela mesma experiência de ter que ficar equilibrando parênteses, tão irritante que levou as pessoas a criarem extensões de editor, é que seria excelente?
Se você quer esse estilo de programação — isto é, baixa densidade sintática e abordagem funcional — faz mais sentido inverter a direção e ir para uma linguagem concatenativa
Fico me perguntando como o resultado compilado de um interpretador Lisp consegue chegar a 3,3 MB
Isso é o tal “desinchar”?
Ainda assim, concordo que distribuir junto uma biblioteca padrão grande com código que não será usado está longe de ser “desinchar”
Choque! Horror!
Que espanto, ter que fechar os parênteses na ordem correta
Até gente que gosta de Lisp e detesta a verbosidade de linguagens como JavaScript costuma recuar diante de linguagens da família APL e passar a defender que clareza e legibilidade são muito mais importantes do que ser o mais curto possível
O autor do LispE parece ter certa afeição pelos operadores básicos de APL, mas ainda assim é difícil entender por que, ao conhecer uma linguagem com notação tão concisa, ele preferiria uma versão do Life de Conway em s-expressões profundamente aninhadas, mais longa e mais espaçada do que as versões em APL, J, K ou até Q