Não há escassez de perguntas vagas sobre "Esquema vs Lisp comum" no StackOverflow e neste site, por isso quero tornar este mais focado. A pergunta é para pessoas que codificaram nos dois idiomas:
Ao codificar no Scheme, de quais elementos específicos da sua experiência em codificação Common Lisp você sentiu mais falta? Ou, inversamente, ao codificar no Common Lisp, o que você perdeu ao codificar no Scheme?
Não quero dizer necessariamente apenas recursos de linguagem. A seguir, todos os itens válidos a serem perdidos, no que diz respeito à pergunta:
- Bibliotecas específicas.
- Recursos específicos de ambientes de desenvolvimento como SLIME, DrRacket etc.
- Recursos de implementações específicas, como a capacidade do Gambit de gravar blocos de código C diretamente na fonte do Scheme.
- E, claro, recursos de linguagem.
Exemplos do tipo de resposta que espero:
- "Eu estava tentando implementar o X no Common Lisp, e se eu tivesse as continuações de primeira classe de Scheme, eu simplesmente teria feito Y, mas, em vez disso, eu tinha que fazer Z, o que era mais doloroso".
- "O script do processo de construção no meu projeto Scheme ficou cada vez mais doloroso à medida que minha árvore de origem cresceu e eu vinculei cada vez mais bibliotecas C. Para o meu próximo projeto, voltei ao Common Lisp."
- "Eu tenho uma grande base de código C ++ existente e, para mim, ser capaz de incorporar chamadas C ++ diretamente no meu código do Gambit Scheme valia totalmente quaisquer deficiências que o Scheme possa ter em relação ao Common Lisp, mesmo incluindo a falta de suporte ao SWIG".
Então, espero histórias de guerra, em vez de sentimentos gerais como "O esquema é uma linguagem mais simples" etc.
Respostas:
Minha graduação era em Ciência Cognitiva e Inteligência Artificial. A partir disso, tive uma introdução de um curso ao Lisp. Eu pensei que a linguagem era interessante (como em "elegante"), mas realmente não pensei muito nisso até que me deparei com a Décima Regra de Greenspun muito mais tarde:
O argumento de Greenspun foi (em parte) que muitos programas complexos têm intérpretes embutidos. Em vez de transformar um intérprete em um idioma, ele sugeriu que faria mais sentido usar um idioma como o Lisp, que já possui um intérprete (ou compilador) embutido.
Na época, eu trabalhava em um aplicativo bastante grande que executava cálculos definidos pelo usuário usando um intérprete personalizado para um idioma personalizado. Decidi tentar reescrever seu núcleo no Lisp como um experimento em larga escala.
Demorou cerca de seis semanas. O código original era de ~ 100.000 linhas de Delphi (uma variante de Pascal). No Lisp isso foi reduzido para ~ 10.000 linhas. Ainda mais surpreendente, porém, foi o fato de o mecanismo Lisp ser 3-6 vezes mais rápido. E tenha em mente que este foi o trabalho de um neófito Lisp! Toda essa experiência foi muito reveladora para mim; pela primeira vez, vi a possibilidade de combinar desempenho e expressividade em um único idioma.
Algum tempo depois, quando comecei a trabalhar em um projeto baseado na Web, testei vários idiomas. Incluí Lisp e Scheme na mistura. No final, selecionei uma implementação Scheme-- Chez Scheme . Fiquei muito feliz com os resultados.
O projeto baseado na Web é um "mecanismo de seleção" de alto desempenho . Usamos o Scheme de várias maneiras diferentes, desde o processamento de dados até a consulta de dados até a geração de páginas. Em muitos pontos, na verdade começamos com um idioma diferente, mas acabamos migrando para o Scheme por razões que descreverei brevemente abaixo.
Agora eu posso responder sua pergunta (pelo menos em parte).
Durante a audição, analisamos várias implementações de Lisp e Scheme. No lado do Lisp, vimos (acredito) Allegro CL, CMUCL, SBCL e LispWorks. No lado do esquema, vimos (acredito) Bigloo, Frango, Chez, Gambit. (A seleção de idioma foi feita há muito tempo; é por isso que estou um pouco enevoado. Posso desenterrar algumas notas, se for importante.)
Logo de cara estávamos procurando a) threads nativas eb) suporte para Linux, Mac e Windows. Essas duas condições combinadas derrubaram todo mundo, exceto (acho) Allegro e Chez - então, para continuar a avaliação, tivemos que afrouxar o requisito de multiencadeamento.
Montamos um conjunto de pequenos programas e os usamos para avaliação e teste. Isso revelou uma série de questões. Por exemplo: algumas implementações tinham defeitos que impediam a execução de alguns testes; algumas implementações não puderam compilar código em tempo de execução; algumas implementações não conseguiram integrar facilmente o código compilado em tempo de execução ao código pré-compilado; algumas implementações tinham coletores de lixo claramente melhores (ou claramente piores) que as outras; etc.
Para nossas necessidades, apenas as três implementações comerciais - Allegro, Chez e Lispworks - passaram nos nossos testes primários. Dos três, apenas Chez passou em todos os testes com cores voadoras. Na época, acho que o Lispworks não tinha threads nativos em nenhuma plataforma (acho que agora) e acho que o Allegro só tinha threads nativos em algumas plataformas. Além disso, a Allegro tinha uma taxa de licenciamento em tempo de execução "que nos chamava", da qual eu não gostava muito. Acredito que o Lispworks não tinha taxa de tempo de execução e o Chez tinha um arranjo simples (e muito razoável) (e só funcionava se você usasse o compilador em tempo de execução).
Tendo produzido partes de código um tanto significativas no Lisp e no Scheme, aqui estão alguns pontos de comparação e contraste:
Os ambientes Lisp são muito mais maduros. Você ganha muito mais dinheiro. (Dito isso, mais código também equivale a mais bugs.)
Os ambientes Lisp são muito mais difíceis de aprender. Você precisa de muito mais tempo para se tornar proficiente; O Lisp comum é uma linguagem enorme - e isso é antes de você chegar às bibliotecas que as implementações comerciais adicionam sobre ela. (Dito isso, o caso de sintaxe de Scheme é muito mais sutil e complicado do que qualquer coisa no Lisp.)
Os ambientes Lisp podem ser um pouco mais difíceis de produzir binários. Você precisa "agitar" sua imagem para remover bits desnecessários e, se você não exercitar seu programa corretamente durante esse processo, poderá acabar com erros de tempo de execução posteriormente. . Por outro lado, com o Chez, compilamos um arquivo de nível superior que inclui todos os outros arquivos necessários e pronto.
Eu disse antes que acabamos usando o Scheme em vários lugares que não pretendíamos originalmente. Por quê? Eu posso pensar em três razões em cima da minha cabeça.
Primeiro, aprendemos a confiar no Chez (e seu desenvolvedor, Cadence). Pedimos muito à ferramenta e ela foi entregue de forma consistente. Por exemplo, o Chez tem historicamente um número trivialmente pequeno de defeitos e seu gerenciador de memória tem sido muito, muito bom.
Segundo, aprendemos a amar o desempenho que recebemos do Chez. Estávamos usando algo que parecia uma linguagem de script - e estávamos obtendo velocidade do código nativo a partir dela. Para algumas coisas que não importavam - mas nunca doía, e às vezes ajudava muito.
Terceiro, aprendemos a amar a abstração que o Esquema poderia proporcionar. A propósito, não me refiro apenas a macros; Quero dizer coisas como fechamentos, lambdas, chamadas finais, etc. Quando você começa a pensar nesses termos, outras línguas parecem bastante limitadas em comparação.
Scheme é perfeito? Não; é uma troca. Primeiro, ele permite que desenvolvedores individuais sejam mais eficazes - mas é mais difícil para os desenvolvedores grunhir o código um do outro, porque as indicações que a maioria dos idiomas possui (por exemplo, para loops) estão ausentes no Scheme (por exemplo, existem milhões de maneiras de fazer um loop for). Segundo, há um grupo muito menor de desenvolvedores para conversar, contratar e emprestar, etc.
Para resumir, acho que diria: Lisp e Scheme oferecem alguns recursos que não estão amplamente disponíveis em nenhum outro lugar. Essa capacidade é uma troca, portanto é melhor que ela faça sentido no seu caso particular. No nosso caso, os fatores determinantes entre escolher o Lisp ou o Scheme tinham mais a ver com recursos muito fundamentais (suporte da plataforma, threads da plataforma, compilação em tempo de execução, licenciamento em tempo de execução) do que com os recursos de idioma ou biblioteca. Novamente, no nosso caso, isso também foi uma troca: com o Chez, obtivemos os principais recursos que queríamos, mas perdemos as extensas bibliotecas que os ambientes comerciais do Lisp tinham.
Além disso, apenas para reiterar: analisamos os vários Lisps e Schemes há muito tempo; todos eles evoluíram e melhoraram desde então.
fonte
Normalmente, não gosto de colar um link como resposta, mas escrevi um artigo de blog sobre isso. Não é exaustivo, mas obtém alguns dos principais pontos.
http://symbo1ics.com/blog/?p=729
Edit : Aqui estão os principais pontos:
TERPRI
,PROGN
etc. O esquema geralmente possui nomes muito sensíveis. Isso é algo perdido no CL.list
" para "lst
" em Esquema.syntax-rules
está tudo bem e elegante até que você queira realmente fazer algumas coisas. Por outro lado, às vezes, as macros higiênicas são perdidas no CL. Não ter uma maneira padrão de fazê-las significa reinventar a roda.Embora eu tenha falado apenas na primeira pessoa um pouco acima, deve ficar claro o que sinto falta e o que não sinto.
[Peço desculpas se estas são muito gerais. Parece que você pode querer detalhes muito mais específicos. Existem alguns detalhes na postagem.]
fonte
Recentemente, iniciei um projeto doméstico usando uma biblioteca que possui uma versão C e uma versão Java. Queria usar o Lisp para o projeto e passei um mês vacilando entre o uso do Common Lisp, Scheme ou Clojure. Eu tenho alguma experiência com todos os três, mas apenas projetos de brinquedos. Vou contar um pouco sobre a minha experiência com cada um deles antes de dizer qual acabei escolhendo.
O PLT Racket possui um bom IDE que não apenas permite avaliar expressões do editor, mas também digita colchetes em vez de parênteses, alternando-os novamente para parênteses, quando apropriado. O Racket também possui um grande conjunto de bibliotecas com a instalação e ainda mais disponíveis para download. O depurador visual também é útil.
Minha implementação Common Lisp (SBCL) não possui um IDE, mas é comum nas implementações de código-fonte aberto CL usar Emacs e SLIME. Essa combinação pode ser muito eficiente. Juntamente com a capacidade de avaliar expressões à medida que você as digita no arquivo de origem, há também um REPL que possui todos os comandos de edição do emacs disponíveis, para que a cópia do código possa ser executada de maneira eficiente nos dois sentidos. Mesmo objetos exibidos no buffer REPL podem ser copiados e colados.
Alt+(
eAlt+)
são eficientes para lidar com parênteses e indentações correspondentes.Todos os recursos acima do Emacs também estão disponíveis para o Clojure. Minha experiência de edição com o Clojure é semelhante à do Lisp. A interoperabilidade Java funcionou bem e eu gostaria de fazer um projeto Clojure assim que amadurecer.
Consegui acessar a biblioteca usando todos os três (Common Lisp, Racket e Clojure), mas acabei escolhendo o Common Lisp para o projeto. O fator decisivo foi que o FFI era muito mais fácil de usar no Common Lisp. O CFFI possui um manual muito bom com código de exemplo e explicações detalhadas de cada método. Consegui agrupar 20 funções C em uma tarde e não precisei tocar no código desde então.
O outro fator é que eu estou mais familiarizado com o Common Lisp do que com o Clojure ou o R6RS Scheme. Eu li a maioria dos livros de Practical Common Lisp e Graham, e me sinto confortável com o Hyperspec. Ainda não é um código "lispy", mas tenho certeza de que isso mudará à medida que eu ganhar mais experiência.
fonte
Eu programa em CL e Racket.
Estou desenvolvendo um site agora no Common Lisp e escrevi um conjunto de programas internos para meu empregador anterior na Racket.
Para o código interno, escolhi o Racket (então conhecido como PLT Scheme) porque o empregador era uma loja do Windows e não conseguia que eles pagassem pelo LispWorks. A única boa implementação de CL de código-fonte aberto para Windows foi (e ainda é) o CCL, que requer suporte SSE no processador. O empregador, por ser barato, estava usando o hardware da Idade da Pedra. Mesmo se o empregador tivesse hardware decente, a única biblioteca de conseqüências da GUI no Common Lisp é o McCLIM, que funciona apenas no Unix. O Racket tem uma boa biblioteca de GUI que funciona tanto no Unix quanto no Windows, o que foi fundamental para o sucesso do meu projeto.
Passei mais de um ano suportando o editor primitivo do DrRacket. O EMACS não conseguiu transformar a versão da GUI do Racket, então conhecida como MrEd, em um cisco inferior no Windows. Eu tive que fazer sem poder avaliar a expressão no cursor com um único toque de tecla. Em vez disso, tive que selecionar manualmente a expressão S, copiá-la, clicar na janela REPL (porque não há pressionamento de tecla para alternar para ela) e colar a expressão S. Eu também tive que ficar sem um editor que pudesse me mostrar os argumentos esperados da função ou macro que eu estava usando. O DrRacket não substitui o SLIME.
O empregador estava usando um banco de dados proprietário com uma API XML complicada que exigia muitas informações aparentemente desnecessárias para poder responder à sua versão de uma consulta SELECT. Decidi usar o HTMLPrag para emitir XML para esta API e analisar as respostas. Funcionou muito bem.
Eu tive que aprender o sistema de macro "caso de sintaxe" complicado de Racket para escrever uma macro que me permitisse interagir com a API XML complicada demais digitando formulários que pareciam SQL. Esta parte teria sido muito mais fácil se eu tivesse o DEFMACRO à minha disposição. No entanto, o resultado final ainda foi perfeito, apesar de ter sido necessário mais esforço para alcançar.
Além disso, eu tive que ficar sem a macro LOOP do Common Lisp. O Racket começou a fornecer uma alternativa somente depois que eu escrevi a maior parte do código, e a alternativa ainda é péssima em comparação com o LOOP (mesmo que a equipe de desenvolvimento do Racket insista que é melhor - eles estão simplesmente errados). Acabei escrevendo muitos formulários LET nomeados que usavam "car" e "cdr" para percorrer as listas.
Falando em carro e cdr, nada é mais frustrante do que a interpretação de Scheme de (car '()) como sendo um erro. Tirei proveito da distinção entre maiúsculas e minúsculas de Racket e implementei o CAR e o CDR, que possuem a semântica do Common Lisp. No entanto, a separação de '() e #f torna muito menos útil retornar' () como um valor padrão.
Também acabei reimplementando UNWIND-PROTECT e inventei meu próprio sistema de reinicialização para preencher a lacuna deixada por Racket. A comunidade Racket precisa aprender que as reinicializações são muito úteis e fáceis de implementar.
O formulário let-values de Racket era excessivamente detalhado, então eu implementei MULTIPLE-VALUE-BIND. Isso foi absolutamente necessário, porque o Racket exige que você receba todos os valores gerados, independentemente de você usá-los ou não.
Mais tarde, tentei escrever um cliente da API XML do eBay no Common Lisp, apenas para descobrir que ele não possui nada como HTMLPrag. HTMLPrag é muito útil. Acabei fazendo esse projeto no Racket. Eu experimentei as instalações de programação alfabetizada de Racket, apenas para descobrir que sou o único programador na Terra que acha mais difícil editar código alfabético escrito corretamente do que o código comum, ou código alfabético incorreto de "comentários excessivos".
Meu novo projeto está sendo realizado no Common Lisp, que foi a escolha certa, porque a comunidade Racket simplesmente não acredita em paralelismo, essencial para este projeto. A única coisa que pensei ter perdido de Racket foram as continuações. No entanto, consegui fazer o que precisava usando reinicializações e, em retrospecto, provavelmente poderia ter feito isso com um fechamento simples.
fonte
cond
formulário, por exemplo) e bugs (eu escrevi o teste de finalização do loop corretamente dessa vez?) Ainda hoje, tenho a impressão esse Racket é destinado principalmente a estudantes e não a programadores profissionais. Toda vez que ouço alguém além de mim usá-lo, eles usam a sub-linguagem "Aluno Iniciante" e é para uma aula.O esquema foi projetado com uma compilação separada em mente. Como conseqüência, o poder de suas macros costuma ser severamente limitado, mesmo com as extensões que permitem um defmacro no estilo Common Lisp, em vez de um sistema macro higiênico limitador e pobre. Nem sempre é possível definir uma macro que defina outra macro, destinada ao uso imediato em uma próxima linha de código. E essa possibilidade é essencial para a implementação de compiladores eDSL eficientes.
Desnecessário mencionar que implementações de esquema com apenas macros higiênicas R5RS são pouco úteis para mim, pois meu estilo de metaprogramação não pode ser adequadamente traduzido em higiene.
Felizmente, existem implementações de esquema (por exemplo, raquete) que não têm essa limitação.
fonte