48 pontos por GN⁺ 10 일 전 | 5 comentários | Compartilhar no WhatsApp
  • As diferenças entre conjuntos de padrões fundamentais são mais importantes do que a gramática individual, e as linguagens de programação se dividem em sete linguagens ur de acordo com repetição, recursão e formas de composição
  • ALGOL, Lisp, ML, Self, Forth, APL e Prolog são as classificações centrais, e cada família usa uma linguagem representativa como amostra de referência para determinar a linhagem de outras linguagens
  • É fácil aprender uma nova linguagem que compartilha uma linguagem ur já familiar, mas ao migrar para um arquétipo desconhecido é necessário um novo caminho de pensamento e um tempo considerável de aprendizado
  • ALGOL se caracteriza pela organização de funções centrada em atribuição, condicionais e laços; Lisp, por macros e código em listas; ML, por funções de primeira classe e recursão; Self, por objetos com passagem de mensagens; Forth, por sintaxe baseada em pilha; APL, por arrays n-dimensionais; e Prolog, por fatos e estrutura de busca
  • Para todo programador, dominar primeiro uma linguagem da família ALGOL é prioridade; em seguida, aprender SQL e depois estudar continuamente linguagens ur menos familiares tende a ser vantajoso no longo prazo

As sete linguagens ur da programação

  • Ao escolher uma linguagem de programação, é mais importante dominar os padrões fundamentais do que as diferenças de gramática individuais; entre linguagens de famílias parecidas, estruturas básicas como percorrer arrays ou percorrer combinações quase sempre têm forma semelhante
  • Famílias de linguagens diferentes variam muito em repetição, recursão e na forma de estruturar programas, e esses conjuntos de padrões fundamentais formam linguagens ur distintas
  • Aprender uma nova linguagem que compartilha uma linguagem ur familiar é uma transição relativamente fácil, mas migrar para uma linguagem ur desconhecida exige bastante tempo e novos caminhos de pensamento
  • As linguagens ur reconhecidas na área de software são sete: ALGOL, Lisp, ML, Self, Forth, APL e Prolog
  • Cada linguagem ur é classificada tomando uma linguagem representativa específica como amostra de referência, e as demais linguagens têm sua linhagem julgada por comparação com essa amostra
  • ALGOL

    • Programas são compostos por sequências de atribuições, condicionais e laços, organizadas em unidades de função
    • Muitas linguagens acrescentam a isso sistemas de módulos, formas de definir novos tipos de dados, polimorfismo e estruturas alternativas de fluxo de controle como exceções ou corrotinas
    • A maior parte das linguagens de programação amplamente usadas hoje pertence a essa família de linguagem ur
    • A própria ALGOL inclui ALGOL 58, ALGOL 60, ALGOL W e ALGOL 68
    • Assembly language, Fortran, C, C++, Python, Java, C#, Ruby, Pascal, JavaScript e Ada se conectam a essa linhagem
    • É a linguagem ur mais antiga, com uma genealogia que remonta à formalização de programas de Ada Lovelace para a máquina analítica de Babbage
    • Tanto a linguagem de máquina e assembly dos computadores de arquitetura Eckert-Mauchly, que levaram ao EDVAC e aos primeiros Univac, quanto as primeiras tentativas de linguagens de alto nível, de A-0 de Grace Hopper até Fortran e COBOL, seguem essa forma
    • Na academia dos anos 1960, o desenvolvimento da programação estruturada tornou essas linguagens mais administráveis, e o resultado foi ALGOL 60, de onde derivou a maior parte dos membros posteriores da família
    • Com o tempo, houve uma tendência de absorver recursos de outras linguagens ur
      • Nos anos 1980, conceitos da família Self foram incorporados na forma de classes e usados como meio de implementar definição de tipos de dados e polimorfismo
      • Depois de 2010, conceitos da família ML também passaram a aparecer
  • Lisp

    • Sintaxe que combina expressões prefixadas entre parênteses e representação em listas
      • (+ 2 3)
      • (defun square (x) (* x x))
      • (* (square 3) 3)
    • Como a representação em listas com itens separados por espaço e envolvidos por parênteses é embutida na linguagem, o próprio código tem forma de lista
    • Macros podem receber listas, modificá-las e passar o código alterado ao compilador, criando uma estrutura em que o programador pode redefinir a semântica da linguagem
    • Na maior parte da escrita de código, ela tende a funcionar como outras linguagens ur, normalmente ALGOL ou ML, mas o sistema de macros é o diferencial
    • A sintaxe loop do Common Lisp também não é um recurso embutido da linguagem, mas algo definido por macro
    • Havia muitas variantes iniciais de Lisp, mas a comunidade acabou chegando a um consenso em torno de Common Lisp
    • Sussman e Steele exploraram até onde era possível ir apenas com funções e criaram Scheme
    • Há usos de Lisp para fins específicos, como Lush para computação numérica, AutoLISP como linguagem de script do AutoCAD e Emacs Lisp para implementar o comportamento do editor Emacs
    • Mais recentemente, Clojure emergiu como o terceiro grande ramo da família Lisp
    • Surgiu cerca de um ano depois de Fortran e é a segunda família de linguagens mais antiga ainda em uso hoje
    • Seu ponto de partida foi uma questão matemática sobre como representar uma estrutura matemática capaz de avaliar suas próprias expressões
    • John McCarthy apresentou a resposta em 1958, e ela depois foi implementada em computadores
    • O Lisp inicial, por sua base matemática, não se encaixava bem nas máquinas da época; questões de memória e ciclos de CPU não existiam na matemática, e técnicas como coleta de lixo tornaram-se necessárias
    • No fim dos anos 1970 e início dos 1980, houve máquinas projetadas do zero apenas para executar Lisp
    • Muitos elementos dos ambientes de desenvolvimento integrados de hoje foram inventados nessas máquinas
    • No mesmo período, Lisp era o principal meio da pesquisa em inteligência artificial, e quando a euforia da IA dos anos 1980 não entregou resultados, Lisp também caiu junto com a área no AI Winter
    • Ainda assim sobreviveu, e com a melhora do desempenho dos computadores e a incorporação de recursos seus por outras linguagens, as dificuldades de implementação diminuíram
  • ML

    • Funções são valores de primeira classe, e a linguagem possui um sistema de tipos da família Hindley-Milner capaz de expressar várias funções e tagged unions
    • Toda repetição é feita por recursão
      • sum [] = 0
      • sum (x:xs) = x + sum xs
    • Também se usa a definição de funções que encapsulam padrões de repetição e implementam o comportamento recebendo outras funções
      • map _ [] = []
      • map f (x:xs) = (f x) : (map f xs)
    • Algumas linguagens, como Miranda e Haskell, usam avaliação preguiçosa por padrão
    • Outras expandem o sistema de tipos em várias direções
      • OCaml tenta combinar-se com conceitos da linguagem ur Self
      • Agda e Idris adotam sistemas de tipos dependentes que misturam valores e tipos
      • 1ML combina módulos e tipos
    • De ML derivaram CaML, Standard ML e OCaml
    • Famílias relacionadas como Miranda, Haskell, Agda e Idris também seguem essa linha
    • ML era a metalinguagem de um programa de prova de teoremas desenvolvido em Cambridge, no Reino Unido, e seu nome vem daí
    • Depois saiu desse contexto e se espalhou como linguagem independente, ganhando popularidade sobretudo na Europa, especialmente no Reino Unido e na França
  • Self

    • Programas são compostos por um conjunto de objetos que trocam mensagens entre si, e todo comportamento é implementado dessa forma
    • Novos objetos são criados enviando mensagens a objetos existentes
    • Até condicionais são realizadas por meio de uma variável que referencia o objeto true ou o objeto false
      • Os dois objetos recebem uma mensagem com, como parâmetros, a função a executar quando for verdadeiro e a função a executar quando for falso
      • O objeto true executa a primeira função, e o objeto false executa a segunda
      • O código chamador não sabe qual objeto é, apenas envia a mensagem
    • Laços funcionam do mesmo modo, e se você criar os objetos corretos e colocá-los nos lugares certos, é possível redefinir toda a semântica da linguagem
    • Essas linguagens normalmente armazenam o código-fonte não em arquivos de texto, mas em um ambiente live
    • O programador modifica o sistema live e salva esse estado, em vez de compilar arquivos para construir o sistema
    • Exemplos importantes são Smalltalk e Self
    • Muitas linguagens adotam apenas parcialmente o estilo de passagem de mensagens dessa família, e essa adoção parcial costuma ser chamada de programação orientada a objetos
    • A maioria delas é baseada em Smalltalk; a única exceção é JavaScript, derivado do sistema de objetos sem classes de Self
    • O sistema de objetos de Common Lisp generaliza isso para que o runtime escolha o código a executar com base não apenas em um objeto receptor de mensagem, mas em todos os parâmetros
    • Erlang muda a direção: em vez de o fluxo de execução migrar entre objetos, threads de execução paralelas escutam e enviam mensagens explicitamente
    • A linguagem original é Smalltalk, desenvolvida no Xerox Parc no fim dos anos 1970 e nos anos 1980
    • Nos anos 1980 houve vários sistemas comerciais de Smalltalk, e a IBM usou Smalltalk no desenvolvimento da coleção de ferramentas de programação VisualAge para outras linguagens
    • Hoje, Smalltalk sobrevive principalmente como o open source Pharo Smalltalk
    • Houve muita pesquisa para executar Smalltalk de forma rápida e eficiente, e o auge disso foi o projeto Strongtalk
    • As descobertas de Strongtalk têm importância histórica por terem servido de base ao compilador JIT HotSpot do Java
    • Smalltalk herdou conceitos de valores e tipos de linguagens anteriores para implementar classes; todo objeto tinha uma classe que lhe atribuía um tipo, e a classe criava objetos desse tipo
    • Self removeu o conceito de classe e passou a ser composto apenas por objetos
    • Por ser uma forma mais pura, Self foi escolhido como amostra de referência dessa linguagem ur
  • Forth

    • Linguagens de pilha são como o espelho invertido de Lisp e compartilham a sintaxe das calculadoras de notação polonesa reversa da Hewlett Packard
    • Elas têm uma pilha de dados; ao escrever um literal como 42, ele é empilhado, e nomes de funções operam sobre a pilha sem parâmetros explícitos
    • Até a aritmética simples fica invertida, como em 2 3 + 5 *
    • A definição de funções também é muito concisa
      • Na maioria das variantes de Forth, : define uma nova palavra
      • square equivale a chamar dup e *
      • dup duplica o topo da pilha, e * multiplica os dois itens do topo
    • É possível interceptar o parser e substituí-lo pelo próprio código, então toda a sintaxe pode ser trocada
    • São comuns programas em Forth que definem pequenas linguagens, como subconjuntos de Fortran, layouts de pacotes ou até uma forma de fazer parsing direto de diagramas ASCII que representam transições de máquina de estados
    • Inclui várias variantes de Forth, além de PostScript, Factor e Joy
    • Joy é uma linguagem funcional pura que usa uma formalização matemática de composição em vez de pilha
    • Forth foi escrito pela primeira vez em 1970 para controle de radiotelescópios
    • Depois se espalhou amplamente por sistemas embarcados
    • Sistemas Forth são fáceis o bastante de fazer bootstrap, e por isso existem dezenas de variantes criadas por programadores para finalidades próprias
    • PostScript surgiu nos anos 1980 como uma forma flexível de descrever documentos em impressoras
    • Em vários aspectos, PostScript é mais restrito que Forth, mas define na linguagem operações básicas ligadas a layout gráfico
  • APL

    • Tudo na linguagem são arrays n-dimensionais
    • Operadores são compostos de um ou dois símbolos e executam operações de alto nível sobre arrays inteiros
    • As expressões são extremamente compactas, a ponto de a própria sequência de símbolos marcar a operação sem necessidade de dar nomes adicionais
    • Por exemplo, calcular a média da variável x toma a forma (+⌿÷≢) x
    • APL, J e K são exemplos representativos
    • Operações de ordem superior sobre arrays foram parcialmente exportadas para vários ambientes como MATLAB, NumPy e R
    • APL começou como uma notação matemática criada por Kenneth Iverson nos anos 1960 e depois foi implementada em computadores
    • Desde então manteve um público de nicho entre pessoas que fazem computação pesada
    • Sua linguagem descendente K foi muito popular no ambiente financeiro
  • Prolog

    • Programas são compostos por um conjunto de fatos
      • father(bob, ed).
      • father(bob, jane).
    • Também se usam fatos não aterrados que derivam fatos a partir de outros fatos com variáveis
      • grandfather(X, Y) :- father(X, Z), father(Z, Y).
    • O runtime de Prolog recebe esses fatos e consultas e realiza uma busca para encontrar resultados
    • Se a estrutura de definição dos fatos for escolhida adequadamente, obtém-se completude de Turing
    • Em Prolog, os termos que compõem fatos são em si um tipo de dado próprio, que pode ser criado e passado ao runtime
    • Nesse ponto, ele ocupa uma posição semelhante à das macros de Lisp ou da substituição do parser em Forth
    • Como programas em Prolog são essencialmente busca, o ajuste de desempenho costuma se concentrar em controlar a ordem da busca e cortar cedo caminhos sem resultado, como em consultas a banco de dados
    • Inclui Prolog, Mercury e Kanren
    • Na prática, a maior parte da programação dessa família de linguagem ur acontece no próprio Prolog, e a comunidade é altamente unificada
    • Nos anos 1970, lógicos franceses perceberam que programas podiam ser expressos em lógica de primeira ordem e começaram a tentar implementá-los
    • Nos anos 1980, o projeto japonês de computadores de quinta geração apostou fortemente em Prolog, mas, com o fracasso do projeto, a reputação de Prolog também caiu
    • Independentemente disso, durante décadas continuaram as pesquisas para tornar o runtime de Prolog eficiente na maioria dos casos e para acrescentar novos recursos
    • Recursos como restrições numéricas foram adicionados, levando à programação lógica com restrições
    • Prolog continua aparecendo em nichos
      • A checagem de tipos do Java foi implementada em Prolog por vários anos
      • A ferramenta inicial de busca em código-fonte do Facebook também era baseada em Prolog

Como aproveitar isso

  • Para a maioria dos programadores, parte ou todas essas famílias de linguagem podem parecer muito estranhas, mas vale investir algum tempo em cada uma pelos caminhos de pensamento e pelas novas possibilidades que elas abrem
  • Do ponto de vista de ALGOL, duas coisas podem parecer completamente diferentes, mas sob outra perspectiva muitas vezes são uma comparação trivial
  • Prioridade

    • Todo programador deve conhecer bem uma linguagem da família ALGOL
    • Em seguida, recomenda-se aprender SQL, uma linguagem da família Prolog
      • Ela ocupa o lugar de segunda maior utilidade ao longo da carreira, depois de ALGOL
  • Expansão posterior

    • Depois de dominar essas duas famílias, compensa no longo prazo aprender, a cada ano, uma nova linguagem de uma família ur desconhecida
    • As linguagens sugeridas em cada família e sua ordem são as seguintes
      • Lisp: PLT Racket
      • ML: Haskell
      • Self: Self
      • Prolog: Prolog
      • Forth: gForth
      • APL: K, via ok
  • Ajustando a ordem

    • Se você faz muita computação numérica, vale aprender K mais cedo
    • Se você trabalha muito com programação embarcada, vale aprender gForth mais cedo
    • Ainda assim, a ordem em si ou a escolha exata da linguagem não são tão importantes
    • Em vez de Haskell, pode-se aprender Standard ML ou OCaml; em vez de PLT Racket, Common Lisp; em vez de gForth, Factor
  • Complementos incluídos nas notas

    • Mesmo depois de aprender SQL, ainda é necessário aprender o próprio Prolog
      • Porque a forma real de uso é bastante diferente de SQL
    • Há também a opinião de um leitor de que, para entender Forth profundamente, uma abordagem comum é implementar você mesmo um runtime de Forth
      • Menciona-se que Forth é pequeno o bastante para que uma pessoa consiga implementá-lo do zero em um tempo relativamente curto
      • gForth é uma boa implementação para aprender ANS Forth
      • Como material de estudo, menciona-se FORTH Fundamentals, Volume 1, de McCabe
      • Outros Forths citados para explorar junto são PygmyForth, eForth e colorForth

5 comentários

 
zkj9404 9 일 전

Interessante.

 
tazuya 9 일 전

Na época da faculdade, aprendi matérias da área e fiz trabalhos com a família ALGOL, Lisp e Prolog, então isso traz boas lembranças.

 
mhcoma 9 일 전

Essas linguagens deixaram muita coisa nas linguagens de programação dominantes de hoje,
mas, entre elas, só Forth parece ter tido menos influência.

 
click 9 일 전

Mesmo sem chegar à notação prefixa, programar em notação pós-fixa é inconveniente demais.

 
GN⁺ 10 일 전
Comentários do Hacker News
  • Nas aulas de PL da Tufts, cheguei a implementar versões mínimas, eu mesmo, das quatro primeiras famílias de linguagens antes de imperativa, Lisp, ML, Smalltalk, e foi bom ver que esse processo agora também virou livro-texto. É uma pena que a parte de Prolog, que existia antes, tenha ficado de fora

    • Se ao menos aparecesse em algum lugar, como no Internet Archive, uma edição incluindo a parte de Prolog, eu acharia ótimo
  • Se eu fosse corrigir só uma coisa na classificação deste texto, diria que Ruby não é tanto da família Algol, e sim claramente uma linguagem orientada a objetos. A influência de Smalltalk é grande, e até nos nomes da biblioteca padrão isso aparece, com coisas como collect em vez de map. Em Ruby, tudo é objeto do começo ao fim, e também é mais natural entender chamadas de método como envio de mensagens a objetos. Ela é muito comparada com Python, mas o caminho evolutivo foi bem diferente, e hoje dá a sensação de que convergiram para ecossistemas parecidos. Para mim, Ruby parece uma alpaca aconchegante mais do que Python

    • Depois de new style classes, Python também pode ser visto na prática como uma linguagem OOP pura. Isso aparece menos num Hello World, mas até os tipos básicos viraram objetos. Para quem não gosta de OOP, mostrar type(42) e dir(42) é uma boa forma de enfatizar que até inteiros são objetos
    • Tenho a impressão de que apontar uma única linguagem ancestral específica como linguagem orientada a objetos acaba confundindo mais as pessoas. OO é mais um estilo de programação, como procedural, do que uma categoria única de linguagem; não acho razoável colocar Python e C++ no mesmo tipo de linguagem só porque ambas têm herança múltipla
    • Falando da metáfora do camelo, camel não era originalmente um símbolo mais ligado a Perl?
  • Eu colocaria mais uma categoria na árvore genealógica das linguagens: as linguagens para expressão de provas. São a família em que programas são provas via correspondência Curry-Howard, e Lean seria um exemplo representativo. Dá para tratá-las como subcategoria do funcional, mas sinto que vale um eixo próprio, porque o objetivo principal é verificação, não execução

    • Para mim, prova de teoremas e tipos complexos parecem extensões acopladas a linguagens já existentes. Agda e Idris são funcionais com tipos complexos adicionados; Isabelle e Lean são isso com prova interativa por cima. Dafny fica mais para um imperativo com teoremas e hints anexados, e ACL2 é fácil de entender como um Lisp com theorem/hint. Além disso, como se vê em Rust traits, typeclasses dão a sensação de ser uma espécie de programação lógica rodando sobre linguagens funcionais e imperativas
    • Por definição, essa família não tem completude de Turing, então acho difícil tratá-la como linguagem de programação de verdade. Se fosse Turing-completa, seria possível fabricar provas falsas com programas que nunca terminam
    • Eu vejo essa linha como algo que no fim das contas deriva diretamente de ML
    • Lean é claramente uma linguagem da família ML com tipos dependentes, próxima de Agda e Idris, então num panorama amplo acho que dá para colocá-la dentro de ML. E também não me parece que o objetivo de longo prazo de Lean seja tratar execução como algo secundário. A Microsoft está interessada em escrever software de verdade. Por outro lado, se você enfatizar mais o aspecto de “linguagem para expressar provas”, então Prolog também não pode ficar de fora, e talvez dê para ver Lean como metade ML, metade Prolog. Nessa perspectiva, a correspondência Curry-Howard parece uma forma de implementar lógica computacional
  • Recentemente voltei a olhar um projeto de comparação de linguagens, e o benchmark fazia decomposição cíclica em paralelo de 3.715.891.200 signed permutations de 10 caracteres. Mais do que “linguagens arquetípicas”, eu queria encontrar, entre as implementações modernas de cada paradigma, linguagens que eu realmente escolheria para programação de pesquisa. Olhei não só desempenho, mas também quão fácil era receber ajuda de IA e quão confortável eu ficava lendo e pensando no código; com a IA, também deu para fazer uma espécie de turismo por otimizações relativamente profundas em cada linguagem. Os resultados estão aqui, e fiquei especialmente surpreso de ver F# no topo

    • À primeira vista parece inesperado, mas acho que os detalhes são a chave. Tirando Lean, no geral as diferenças numéricas não são tão dramáticas, e o fato de Chez ser 2,5 vezes mais lento que C++ ainda é um desempenho bem respeitável para uma linguagem JIT dinamicamente tipada. O motivo de F# ir tão bem nesse tipo de tarefa provavelmente é que a experiência de paralelismo em .NET Core é especialmente madura e sólida. Se esses números forem elapsed time, seria ainda mais interessante ver também a decomposição em CPU time. Além disso, a estratégia de paralelização varia um pouco de linguagem para linguagem, então não é uma comparação sob condições totalmente idênticas. Por exemplo, a simples divisão em threads de F# e o parallel iterator do Rayon em Rust podem ter estruturas de overhead diferentes. No fim, Rust e C++ talvez possam ir mais longe se você tratar cuidadosamente os primitivos de concorrência de baixo nível do SO, mas isso já seria outro tipo de comparação. Também fica ambíguo se seria justo permitir uso de C FFI em C ou Haskell, então esse tipo de comparação inevitavelmente mistura bastante julgamento qualitativo. A propósito, no código de Chez talvez haja espaço para acelerar mais colocando permutations em fxvector e usando operações especializadas para fixnum, reduzindo boxing/unboxing e alocação. A documentação relevante está na documentação de objetos do Chez Scheme
  • Eu também escrevi algo parecido aqui. Concordo com Algol, Lisp, Forth, APL, Prolog, mas para linguagem funcional inovadora coloquei SASL, um pouco anterior a ML, e como representante de orientação a objetos escolhi Smalltalk, que veio antes de Self. Também incluí Fortran, COBOL, SNOBOL e Prograph, por achar que cada uma mudou o jogo à sua maneira

    • Gosto mais dessa lista. Fiquei especialmente contente de ver SNOBOL nela. Nunca usei, mas foi uma das linguagens que conheci quando era criança ao pegar um livro sobre ela num saldão de livros da biblioteca pública só porque o nome parecia divertido. Antes disso eu só conhecia um pouco de BASIC, Logo e um pouco de assembly 6502 que chamei a partir de BASIC seguindo exemplos do manual do Atari BASIC. Também é difícil imaginar uma lista de linguagens inovadoras sem Fortran e COBOL, ou mesmo sua raiz, FLOW-MATIC. O livro de referência era o manual do Atari BASIC
    • Não entendo bem por que Smalltalk em vez de Self não entrou na lista. Smalltalk veio antes, e Alan Kay foi justamente a pessoa que criou o próprio nome “OOP”. E ML também costumo ver como descendente de Lisp
  • Eu gostaria de adicionar a esta discussão as famílias semânticas. Coisas como Verilog, Petri nets, Kahn process networks, dataflow machines, process calculi, reactive, term rewriting, constraint solver/theorem prover, probabilistic programming e afins. Também me vêm à cabeça linguagens como Unison, Darklang, temporal dataflow e DBSP, que não se encaixam perfeitamente nas 7 categorias existentes, mas na prática estão perto de produção. Pode soar como trapaça, mas a maioria delas representa modelos de computação paralelos ao modelo de máquina de von Neumann. Faz tempo que tenho vontade de escrever algo como “todas as formas de computação que conhecemos, para além de von Neumann”

    • Eu leria esse texto com enorme prazer se ele saísse. Enquanto isso, isso me fez lembrar de partes de um texto do Steve Yegge. A ideia central era que boa parte do ensino moderno de CS está, na prática, em cima da estrutura criada por von Neumann, e que a escolha por um dispositivo sequencial refletia os custos e as limitações de velocidade da manufatura da época. Também me marcou a observação de que muito do que aprendemos sobre arquitetura de máquinas, desvios, laços, sub-rotinas, depuração, conversão de sistemas numéricos e modelagem de problemas já estava no trabalho dele. A citação relacionada está no archive
    • Ao ver a menção a term rewriting, lembrei de quando, na faculdade, eu fiz um software de planilha e fiquei responsável pelo parser de fórmulas. Fiquei travado a semana inteira, mas no fim percebi que, se eu reescrevesse 1+1 como ADD(1,1), eu conseguia fazer o parsing do jeito que sabia. Além disso, eu me recusava sem motivo a aprender regex, então o código ficou bastante esquisito, e ainda lembro de um colega dizendo “se o Andy diz que consegue, então não vamos mexer”. Outra pessoa do time resolveu a mesma coisa com regex em um código talvez 20 vezes menor que o meu
    • Sobre a ideia de “linguagens emergentes prontas para uso real”, no meu critério até sistemas como o ChatGPT, embora ainda não totalmente production-ready, entram numa categoria parecida por já serem usados no trabalho de verdade. É discutível chamá-los de linguagem de programação, mas no sentido de serem um meio pelo qual humanos dizem a computadores o que fazer, acho perfeitamente razoável. E o fato de serem não determinísticos também não me parece desqualificá-los como linguagem de programação
    • Acho que o texto do Sussman sobre propagators também vale a leitura
    • Como exemplo de logic programming em S9 Scheme, achei este material bom. Não é preciso nem comprar o livro: dá para baixar o código direto, e depois de pegar o básico com um introdutório como Simply Scheme, a estrutura do solver fica bem fácil de acompanhar
  • “Concepts of programming languages”, que fiz na TU Delft, foi minha disciplina favorita em computação. Aprendemos C, Scala para a parte funcional e JavaScript para o conceito de protótipos, e isso me ajudou muito quando fui aprender Elixir alguns anos depois. Também havia uma aula em que se escrevia um agente de Unreal Tournament em GOAL, uma linguagem baseada em Prolog. Durante muito tempo eu não consegui imaginar onde usar Prolog, mas no fim acabei usando para criar um corretor ortográfico que fazia ajustes iterativos em frases ruins em papiamentu geradas por LLM

    • Também fiz uma disciplina parecida e, embora o professor não fosse grande coisa, sinto que foi uma das melhores matérias que cursei. Só de conhecer, mesmo que superficialmente, outras linguagens arquetípicas, sua visão já se amplia bastante, e com assembly isso fica ainda mais forte. Talvez você nunca produza nada útil diretamente com elas, mas pelo menos evita a armadilha de tratar todo problema como prego só porque tem um martelo na mão
    • Eu também estava nessa disciplina. A parte de Unreal Tournament foi uma das aulas mais legais que já vi, e lembro que ela sumiu no ano seguinte. Pena que agora parece ter virado uma aula comum de IA, como todas as outras. Ainda não encontrei muitos bons usos para Prolog, mas GOAL me impressionou muito mais. E só recentemente percebi, com certa frustração, que dá para reproduzir essa estrutura em linguagens mais “normais” também, e com várias vantagens
    • Fiquei curioso se o GOAL citado aqui é Game Oriented Assembly Lisp
  • Concordo com a ideia de que é preciso aprender linguagens de categorias diferentes. Só depois de aprender OCaml as funções realmente começaram a parecer funções matemáticas para mim, e Mathematica me ensinou a olhar para expressões como entrada em si. A notação polonesa reversa do PostScript não mexeu só com aritmética simples; pareceu literalmente religar meu modo de pensar. Por outro lado, não concordo com a ideia de que tanto faz escolher Java, C#, C++, Python ou Ruby. Se o objetivo for apenas implementar quicksort, talvez pareçam parecidas, mas para quem quer realmente construir alguma coisa, a escolha da linguagem faz uma diferença de dia e noite. Se você colocar Ruby na mão de alguém que quer fazer jogos 3D, ou Java na mão de alguém que quer fazer ciência de dados exploratória ou deep learning, isso pode matar a motivação

    • Eu provavelmente nunca vou ganhar dinheiro com Rust também, mas não me arrependo nem um pouco de tê-la aprendido. Rust me obrigou a pensar muito profundamente sobre propriedade de dados dentro de programas
  • Este texto me lembrou 7 languages in 7 weeks, do Bruce Tate. Foi por esse livro que conheci Erlang. Ainda assim, historicamente me parece um pouco forçado colocar COBOL e Fortran dentro da família Algol, embora isso também sirva para lembrar que história é, por natureza, um tipo de organização redutiva até certo ponto

    • Indo ainda mais para trás, também acho difícil fixar uma classificação primitiva. As primeiras linguagens assembly já eram imperativas, mas o que tornou Algol, Fortran e Cobol interessantes foi terem possibilitado programação complexa por meio de funções e outros recursos de alto nível. Algol acabou gerando mais descendentes, mas considero Fortran a primeira linguagem de programação imperativa
    • Só olhando a Wikipedia, parece que Fortran e Algol foram desenvolvidas ambas por volta de 1957, mas fiquei curioso sobre qual surgiu primeiro na prática e se houve influência mútua ou sobreposição no processo de design
    • Talvez o mais certo seja ver COBOL como um fóssil vivo. E o Fortran de hoje me parece uma linguagem baseada na linhagem FORTRAN, mas que recebeu horizontalmente características da família Algol
  • Já houve uma discussão antiga no HN sobre isso. A discussão anterior ajuda a entender melhor o contexto

    • Mais precisamente, foi a discussão de 4 de maio de 2023, com 323 comentários. E, mais antiga ainda, houve esta thread, de 30 de setembro de 2021, que teve 29 comentários