C # Dev - Eu tentei o Lisps, mas não o entro [fechado]

37

Depois de alguns meses aprendendo e brincando com Lisp, CL e um pouco de Clojure, ainda não vejo uma razão convincente para escrever algo nele em vez de C #.

Eu realmente gostaria de algumas razões convincentes, ou para alguém ressaltar que estou sentindo falta de algo realmente grande .

Os pontos fortes do Lisp (de acordo com minha pesquisa):

  • Notação compacta e expressiva - Mais do que C #, sim ... mas também consigo expressar essas idéias em C #.
  • Suporte implícito à programação funcional - C # com métodos de extensão LINQ:
    • mapcar = .Selecione (lambda)
    • Mapcan = .Selecione (lambda) .Aggregate ((a, b) => a.União (b))
    • carro / primeiro = .Primeiro ()
    • cdr / rest = .Skip (1) .... etc.
  • Suporte a funções Lambda e de ordem superior - C # possui isso, e a sintaxe é sem dúvida mais simples:
    • "(lambda (x) (corpo))" versus "x => (corpo)"
    • "# (" com "%", "% 1", "% 2" é bom no Clojure
  • Envio de método separado dos objetos - o C # tem isso através de métodos de extensão
  • Despacho multimétodo - o C # não possui isso nativamente, mas eu poderia implementá-lo como uma chamada de função em algumas horas
  • Código é dados (e macros) - Talvez eu não tenha "recebido" macros, mas não vi um único exemplo em que a idéia de uma macro não pudesse ser implementada como uma função; isso não muda a "linguagem", mas não tenho certeza se isso é uma força
  • DSLs - Só pode fazê-lo através da composição de funções ... mas funciona
  • Programação "exploratória" não tipada - para estruturas / classes, as propriedades automáticas do C # e o "objeto" funcionam muito bem, e você pode escalar facilmente para uma digitação mais forte à medida que avança
  • É executado em hardware que não é Windows - Sim, é? Fora da faculdade, conheci apenas uma pessoa que não executa o Windows em casa ou pelo menos uma VM do Windows no * nix / Mac. (Então, novamente, talvez isso seja mais importante do que eu pensava e acabei de fazer uma lavagem cerebral ...)
  • O REPL para o projeto de baixo para cima - Ok, admito que isso é realmente muito bom e sinto falta dele em C #.

Coisas que estou perdendo no Lisp (devido a uma mistura de C #, .NET, Visual Studio, Resharper):

  • Namespaces. Mesmo com métodos estáticos, eu gosto de amarrá-los a uma "classe" para categorizar seu contexto (Clojure parece ter isso, CL não parece).
  • Excelente compilação e suporte em tempo de design
    • o sistema de tipos permite determinar a "correção" das estruturas de dados que eu passo
    • qualquer erro de ortografia é sublinhado em tempo real; Eu não tenho que esperar até o tempo de execução para saber
    • melhorias de código (como usar uma abordagem FP em vez de uma abordagem imperativa) são sugeridas automaticamente
  • Ferramentas de desenvolvimento da GUI: WinForms e WPF (sei que o Clojure tem acesso às bibliotecas da GUI do Java, mas são totalmente estranhas para mim).
  • Ferramentas de depuração da GUI: pontos de interrupção, entrada e saída, inspetores de valor (texto, xml, personalizado), relógios, depuração por segmento, pontos de interrupção condicionais, janela de pilha de chamadas com a capacidade de ir para o código em qualquer nível na pilha
    • (Para ser justo, minha passagem pelo Emacs + Slime parecia fornecer parte disso, mas sou parcial com a abordagem orientada a VS GUI)

Eu realmente gosto do hype em torno de Lisp e dei uma chance.

Mas há algo que eu possa fazer no Lisp que não possa fazer tão bem em C #? Pode ser um pouco mais detalhado em C #, mas também tenho preenchimento automático.

o que estou perdendo? Por que devo usar o Clojure / CL?

talonx
fonte
4
Como você já está programando em um estilo funcional e parece que confia bastante na infraestrutura do Windows, não vejo nenhum motivo convincente para você mudar do C #. A maioria das pessoas que conheço usa Mac ou Linux, portanto depende muito da multidão com a qual você trabalha (eu usei todas as versões do Windows desde o 3.1, mas ainda prefiro trabalhar com software de plataforma cruzada e sistemas * nix em geral ... mas então eu não faço qualquer trabalho nativo GUI, todos os servidores e coisas UI web)
Sean Corfield
2
Você pode dar uma olhada no The Swine Before Perl . É uma conversa divertida de se ouvir e apresenta um exemplo simples de para que servem as macros.
Matthias Benkard
4
"Não vi um único exemplo em que a idéia de uma macro não pudesse ser implementada como uma função" - gostaria de ver como você escreveria ANDou ORcomo uma função. Isso poderia ser feito (dado LAMBDA, o que também é uma macro), mas não vejo uma maneira óbvia de fazê-lo que não seja totalmente ruim.
11
"Namespaces. ... Clojure parece ter isso, CL parece não ter" - você pode ser mais específico sobre o que está procurando? Eu realmente não usei o Clojure, mas seus namespaces se parecem muito com os pacotes do CL.
4
Jonathan: CL usa :(ou ::para símbolos não exportados) para nomear símbolos em pacotes, por exemplo, seu exemplo aqui usaria http:sessione chat:session.

Respostas:

23

As macros permitem escrever compiladores sem deixar o conforto do seu idioma. DSLs em idiomas como C # geralmente equivalem a um intérprete de tempo de execução. Dependendo do seu domínio, isso pode ser problemático por razões de desempenho. A velocidade importa , caso contrário, você codificaria em uma linguagem interpretada e não em C #.

Além disso, as macros também permitem considerar fatores humanos - qual é a sintaxe mais amigável para uma DSL específica? Com o C #, não há muito o que fazer sobre a sintaxe.

Portanto, o Lisp permite que você participe do design da linguagem sem sacrificar o caminho para a eficiência . E, embora esses problemas possam não ser importantes para você , eles são extremamente importantes, pois estão na base de todas as linguagens de programação úteis orientadas à produção. Em C #, esse elemento fundamental é exposto a você de uma forma muito limitada, na melhor das hipóteses.

A importância das macros não se perde em outros idiomas - o modelo Haskell, camlp4 vem à mente. Mas, novamente, é uma questão de usabilidade - as macros Lisp até o momento são provavelmente a implementação mais amigável e poderosa da transformação em tempo de compilação.

Então, em resumo, o que as pessoas geralmente fazem com idiomas como C # é criar DSILs (Domínios Interpretados Específicos de Domínio). O Lisp oferece a oportunidade de criar algo muito mais radical, DSPs (Domain Specific Paradigms). O Racket (anteriormente PLT-Scheme) é particularmente inspirador nesse sentido - eles têm uma linguagem preguiçosa (Lazy Racket), um tipo digitado (Typed Racket), Prolog e Datalog, todos incorporados linguisticamente por macros. Todos esses paradigmas fornecem soluções poderosas para grandes classes de problemas - problemas que não são melhor resolvidos por programação imperativa ou mesmo paradigmas de PF.

Robert Harvey
fonte
3
O que acho interessante sobre esse argumento é que nunca tive uma oportunidade (ou simplesmente a ignorei na minha ignorância) para implementar um DSL / DSIL. Você poderia elaborar sobre o poder das DSLs? (Tanto para um desenvolvedor quanto para um usuário.) Isso parece ser a coisa mais importante que realmente sinto falta.
15
@ Jonathan Mitchem, você já está usando muitos DSLs externos - arquivos de configuração, scripts de compilação, configurações ORM, geradores de código visual (por exemplo, editor de winforms), XAML, geradores de analisador, etc. DSLs incorporados são ainda melhores, assim como você precisa de uma ferramenta de compilação separada para eles, e eles são exibidos em um único idioma. E você deve estar familiarizado com pelo menos duas das DSLs incorporadas - expressões regulares e SQL.
SK-logic,
Uau OK. Eu nunca pensei neles como DSLs. Agora, intencionalmente, me afastei de muito disso, com base em "qualquer coisa que eu possa fazer com c #, vou ficar com c # para". Eu gosto de ficar com uma ferramenta com um comportamento consistente, pessoalmente. Mas eu entendo o valor das DSLs nesses exemplos.
2
@ Jonathan Mitchem, o problema com qualquer ferramenta é que ela não será necessariamente adequada para um determinado objetivo. Você precisa escolher ferramentas diferentes para tarefas diferentes. E o poder de qualquer meta-linguagem, incluindo o Lisp, é que você não precisa mudar completamente para outra ferramenta, pois pode aumentar suas próprias ferramentas específicas de domínio sobre o idioma principal. Sugiro que você dê uma olhada em Nemerle, seria mais fácil entendê-lo para um desenvolvedor de C # e suas macros são quase tão poderosas quanto as de Lisp.
SK-logic
3
"Eu gosto de ficar com uma ferramenta ..." As DSLs criadas corretamente no Lisp nunca escondem todo o poder do Lisp, então você ainda tem uma ferramenta. Eles apenas aumentam o vocabulário de uma maneira que torna a codificação de um domínio específico mais "natural", ou seja, com melhores abstrações e organização geral.
15

Quase tudo o que estava originalmente disponível apenas no Lisps, felizmente, migrou para muitas outras línguas modernas. A maior exceção é a filosofia "código é dados" e macros.

Código é dados (e macros) - Talvez eu não tenha "recebido" macros, mas não vi um único exemplo em que a idéia de uma macro não pudesse ser implementada como uma função

Sim, é difícil criar macros. A metaprogramação em geral é difícil de entender. Se você viu alguma macro que pudesse ser implementada como uma função, o programador estava fazendo errado. As macros devem ser usadas apenas quando uma função não funcionar.

O exemplo "olá mundo" de uma macro é escrever "se" em termos de cond. Se você estiver realmente interessado em aprender o poder das macros, tente definir um "my-if" no clojure, usando funções e observe como ele se quebra. Não pretendo ser misterioso, nunca vi alguém começar a entender macros apenas por explicação, mas esta apresentação de slides é uma introdução muito boa: http://www.slideshare.net/pcalcado/lisp-macros-in -20-minutos-com-apresentação-clojure

Eu tive pequenos projetos nos quais salvei literalmente centenas / milhares de linhas de código usando macros (em comparação com o que seria necessário em Java). Grande parte do Clojure é implementada no Clojure, o que só é possível por causa do sistema macro.

mblinn
fonte
3
Sem tocar em nenhum código, passei pelo cenário de implementação de um "se" sem macros na minha cabeça, tanto no Clojure quanto no C #. Efetivamente (ou literalmente) não pode ser feito. Eu admito que é legal. Mas estou sentindo falta da conexão de como isso é útil para mim. O que posso fazer com macros (além de escrever "se") que não posso fazer com design funcional ou OO inteligente? "Como isso pode me ajudar" não é um critério válido para avaliar um idioma, mas é para avaliar se vou usá-lo. (Eu realmente quero um Lisp para valer a pena comutação para, mas não atingiu o ponto de se tornar uma alternativa viável.)
11
Vai levar um tempo para entender esse exemplo. Para mim, "salvar código padrão" normalmente invoca o termo "refatoração", que é parte do motivo pelo qual as explicações não me convenceram. Eu tenho uma solução que funciona em todos os casos em que a apliquei. Acho que a pergunta é como você identifica casos em que pode usar uma macro?
11
Concordo que as macros valem a pena, mas não é verdade que um my-if as exija, ele pode ser gravado como uma função de ordem superior (veja um exemplo de CL abaixo). Você realmente só precisa de macros se quiser percorrer o código ou colocá-lo em um novo contexto lexical. (defun my-if (test then &optional else) (cond (test (funcall then)) ('otherwise (funcall else))))
11
Basicamente, com uma função, você tem a opção de aceitar o código citado, o qual você pode percorrer, mas está faltando o contexto lexical porque você está andando e executando-o no contexto lexical da sua função. Ou você pode aceitar fechamentos, que mantêm o contexto lexical deles, mas você pode apenas ligar, não orientá-los ou adicionar algo ao contexto lexical deles. Para fazer as duas coisas, você precisa de uma macro, que pode percorrer e agrupar o código antes que sua expansão seja colocada no contexto lexical da chamada de macro.
7
@ Jonathan Mitchem, a sintaxe do LINQ é um bom exemplo do que pode ser feito com macros, mas teve que ser implementada no núcleo da linguagem, pois ela não suporta nenhuma metaprogramação decente.
SK-logic,
14

Não sou especialista em Common Lisp, mas conheço o C # e o Clojure razoavelmente bem; espero que essa seja uma perspectiva útil.

  • Sintaxe simples => power - Lisps são a sintaxe mais simples possível. Expressões S são tudo que você precisa. Uma vez que você grokked "(função-chamada arg1 arg2 arg3)", então você basicamente tem. O resto é apenas escolher as chamadas e argumentos de função corretos. Parece quase trivialmente simples, mas o fato é que essa simplicidade é o que dá a Lisps tanta força e flexibilidade e, em particular, habilita os recursos de metaprogramação pelos quais Lisp é famoso. por exemplo, se eu quiser uma macro para chamar várias funções diferentes nos mesmos argumentos que apenas fazer algo como o seguinte (não este é não aplicação de função apenas de tempo de execução - é uma macro que gera o código compilado como se você tivesse escrito a todas as chamadas de função individuais à mão):
(defmacro print-many [functions args]  
  `(do   
     ~@(map   
        (fn [function] `(println (~function ~@args)))   
        functions)))

(print-many [+ - * /] [10 7 2])  
19  
1  
140  
5/7
  • Como resultado da sintaxe incrivelmente simples, a filosofia de "código é dados" de Lisp é muito mais poderosa do que qualquer coisa que você possa fazer com composição de funções / modelos / genéricos etc. É mais do que apenas DSLs, é geração e manipulação de código, em tempo de compilação , como uma característica fundamental da linguagem. Se você tentar obter esse tipo de recursos em uma linguagem não homoicônica como C # ou Java, acabará reinventando muito o Lisp. Daí a famosa Décima Regra de Greenspuns: "Qualquer programa C ou Fortran suficientemente complicado contém uma implementação lenta ad hoc, especificada informalmente, cheia de bugs e com erros, de metade do Common Lisp". Se você já inventou uma linguagem de controle de fluxo / modelagem completa em seu aplicativo, provavelmente já sabe o que quero dizer .....

  • A simultaneidade é uma força única do Clojure (mesmo em relação a outros Lisps), mas se você acredita que o futuro da programação significará ter que escrever aplicativos que escalam para máquinas com vários núcleos, então você realmente deve analisar isso - é bastante inovador. O Clojure STM (Memória Transacional de Software) funciona porque o Clojure adota imutabilidade e construções de simultaneidade sem bloqueio com base em uma nova separação de identidade e estado (consulte o excelente vídeo de Rich Hickey sobre identidade e estado ). Seria muito doloroso enxertar esse tipo de capacidade de simultaneidade em um ambiente de idioma / tempo de execução em que uma proporção significativa das APIs trabalha em objetos mutáveis.

  • Programação funcional - os Lisps enfatizam a programação com funções de ordem superior. Você está certo de que ele pode ser emulado em objetos OO com objetos de fechamento / função etc., mas a diferença é que todo o idioma e a biblioteca padrão foram projetados para ajudá-lo a escrever código dessa maneira. Por exemplo, as sequências do Clojure são preguiçosas , portanto podem ser infinitamente longas, diferentemente de ArrayLists ou HashMaps em C # / Java. Isso faz com que alguns algoritmos muito mais fácil de expressar, por exemplo, os seguintes implementos uma lista infinita de números de Fibonacci:

    (def fibs (lazy-cat '(0 1) (map + fibs (drop 1 fibs))))

  • Digitação dinâmica - os Lisps tendem a estar no final "dinâmico" do espectro da linguagem de programação funcional (em oposição a idiomas como Haskell, com uma concepção muito forte e bonita de tipos estáticos). Isso tem vantagens e desvantagens, mas eu argumentaria que as linguagens dinâmicas tendem a favorecer a produtividade da programação devido à maior flexibilidade. Essa digitação dinâmica tem um custo menor de desempenho em tempo de execução, mas se isso o incomoda, você sempre pode adicionar dicas de tipo ao seu código para obter digitação estática. Basicamente - você obtém conveniência por padrão e desempenho, se estiver disposto a fazer um pouco de trabalho extra para obtê-lo.

  • Desenvolvimento interativo - na verdade, acho que você pode obter algum tipo de REPL para C # 4.0, mas no Lisp é uma prática padrão e não uma novidade. Você não precisa executar um ciclo de compilação / construção / teste - você escreve seu código diretamente no ambiente em execução e apenas o copia posteriormente nos arquivos de origem. Ele ensina uma maneira muito diferente de codificar, onde você vê resultados imediatamente e refina sua solução de forma iterativa.

Alguns comentários rápidos sobre o que você vê como "ausente":

  • Como você diz, Clojure tem namespaces. Na verdade, eles são espaços de nome dinâmicos: você pode atualizá-los em tempo de execução - isso fornece alguns benefícios surpreendentes para o desenvolvimento interativo. Eu me diverti muito redefinindo funções sob o nariz de um thread em execução ou cortando uma estrutura de dados ao vivo ....
  • Suporte ao tempo de compilação / design - não é realmente relevante se você estiver codificando em um REPL - basta fazê-lo e ver o resultado diretamente. Dito isto, o Clojure está começando a obter suporte aprimorado para IDE, por exemplo, o plugin CounterClockwise para Eclipse .
  • Desenvolvimento de GUI - Sim, você terá que aprender uma nova API, mas isso sempre será o caso ao alternar linguagens .... a boa notícia é que as APIs Java não são tão difíceis e agora existem alguns Clojure- invólucros / exemplos específicos que parecem bem fáceis de usar. Veja esta pergunta no desenvolvimento da interface gráfica do usuário Clojure para obter alguns bons exemplos
  • Depuração da GUI: isso funciona com o depurador da GUI no Eclipse, assumindo que você use CounterClockwise ou Enclojure se você usa o Netbeans. Dito isto, não uso esse recurso - acho a depuração interativa no REPL mais produtiva.

Pessoalmente, considero as vantagens do Clojure / Lisp bastante atraentes e não pretendo voltar ao C # / Java (além do que eu preciso emprestar todas as bibliotecas úteis!).

No entanto, demorou alguns meses para eu realmente entender tudo. Se você está realmente interessado em aprender o Lisp / Clojure como uma experiência de aprendizado esclarecedora, não há substituto para mergulhar e se forçar a implementar algumas coisas ...

Mikera
fonte
11
Obrigado pela grande enumeração de idéias. Na verdade, eu uso muito sequências preguiçosas por meio da construção IEnumerable <> em C # (e não toquei em um ArrayList desde 2005 ou mais), mas entendo a idéia. As primitivas de simultaneidade de Clojure são extremamente impressionantes. Eu fazia computação em grade em C # há alguns anos - simultaneidade em muitas máquinas com vários núcleos - e ainda acredito que seja o futuro. Provavelmente, a maior idéia que recebi de todos é "você realmente precisa se aprofundar e experimentar, não pode ser realmente explicado". Então, eu vou continuar cavando e continuando experimentando.
11
Legal, feliz por ter ajudado - e esse é absolutamente o espírito certo !!
Mikera
10

O C # possui muitos recursos, mas o mix parece diferente. O fato de alguma linguagem ter uma característica ainda não significa que seja fácil de usar, paradigmático e bem integrado ao restante da linguagem.

Lisp comum tem esta mistura:

  • expressões-s como uma sintaxe de dados
  • codificar como dados leva a macros e outras técnicas de computação simbólica
  • linguagem dinâmica permite modificações em tempo de execução (ligação tardia, MOP, ...)
  • fortemente tipado, dinamicamente
  • uso interativo com compilador ou intérprete incremental
  • Avaliador como mecanismo de execução principal
  • memória gerenciada com Garbage Collection
  • Linguagem híbrida com uso intenso de programação imperativa, funcional e orientada a objetos. Outros paradigmas podem ser adicionados (regras, lógica, restrições, ...).

Agora, outros idiomas, como C #, também têm isso. Mas muitas vezes não com a mesma ênfase.

C # tem

  • Sintaxe C
  • orientado a objetos, principalmente imperativos, com alguns recursos de FP
  • digitado estaticamente
  • principalmente uso em lote com um compilador em lote
  • memória gerenciada com Garbage Collection

Não ajuda que o C # tenha, por exemplo, recursos de manipulação de código, se não forem amplamente utilizados como no Lisp. No Lisp, você não encontrará muitos softwares que não fazem uso pesado de macros de todas as formas simples e complexas. Usar manipulação de código é realmente um grande recurso no Lisp. Emular alguns usos é possível em muitos idiomas, mas não o torna um recurso central como no Lisp. Veja livros como 'On Lisp' ou 'Practical Common Lisp' para exemplos.

O mesmo para desenvolvimento interativo. Se você desenvolver um grande sistema CAD, a maior parte do desenvolvimento será interativa a partir do editor e do REPL - diretamente no aplicativo CAD em execução. Você pode emular muito disso em C # ou em outros idiomas - geralmente implementando um idioma de extensão. Para Lisp, seria estúpido reiniciar o aplicativo CAD em desenvolvimento para adicionar alterações. O sistema CAD também conteria um Lisp aprimorado que incluiria recursos de linguagem (na forma de macros e descrições simbólicas) para descrever objetos CAD e seus relacionamentos (parte de, contido, ...). Pode-se fazer coisas semelhantes em C #, mas no Lisp esse é o estilo de desenvolvimento padrão.

Se você desenvolver software complexo usando um processo de desenvolvimento interativo ou se o seu software tiver uma parte simbólica substancial (metaprogramação, outros paradigmas, álgebra computacional, composição musical, planejamento, ...), o Lisp pode ser o seu caso.

Se você trabalha no ambiente Windows (não), o C # tem uma vantagem, pois é a principal linguagem de desenvolvimento da Microsoft. A Microsoft não suporta nenhum formulário Lisp.

Você escreve:

  • Namespaces. Mesmo com métodos estáticos, eu gosto de amarrá-los a uma "classe" para categorizar seu contexto (Clojure parece ter isso, CL não parece).

O Lisp comum não anexa namespaces às classes. Os espaços para nome são fornecidos pelos pacotes de símbolos e são independentes das classes. Você precisa reorientar sua abordagem à programação orientada a objetos se você usar o CLOS.

  • Excelente compilação e suporte em tempo de design, o sistema de tipos me permite determinar a "correção" das estruturas de dados que eu passo em torno de qualquer coisa digitada incorretamente, sendo sublinhada em tempo real; Não preciso esperar até o tempo de execução para saber que as melhorias de código (como usar uma abordagem FP em vez de uma abordagem imperativa) são sugeridas automaticamente

Use o compilador Lisp. Informa sobre variáveis ​​desconhecidas, pode ter recomendações de estilo (dependendo do compilador usado), fornece dicas de eficiência, ... O compilador está pressionado uma tecla.

  • Ferramentas de desenvolvimento da GUI: WinForms e WPF (sei que o Clojure tem acesso às bibliotecas da GUI do Java, mas são totalmente estranhas para mim).

Os Lisps comerciais como LispWorks e Allegro CL oferecem coisas semelhantes no Windows.

  • Ferramentas de depuração da GUI: pontos de interrupção, entrada e saída, inspetores de valor (texto, xml, personalizado), relógios, depuração por segmento, pontos de interrupção condicionais, janela de pilha de chamadas com a capacidade de ir para o código em qualquer nível na pilha (para ser justo, minha passagem pelo Emacs + Slime parecia fornecer um pouco disso, mas sou parcial com a abordagem orientada a VS GUI)

Os Lisps comerciais como LispWorks e Allegro CL oferecem tudo isso no Windows.

Rainer Joswig
fonte
11
Minhas críticas não são realmente sobre Lisps. Acho que eles são bastante capazes. Estou procurando o que um Lisp pode fazer / me dar que eu ainda não faço. Entendo perfeitamente que a maioria dos desenvolvedores de C # não usa muitos dos "novos" recursos de linguagem. Acho que o ponto mais importante é que, honestamente, fora da GUI, quase escrevo em um estilo 100% FP. FP foi um salto conceitual, mas vale a pena. No entanto, mudar para um Lisp de onde estou parece fornecer pouco benefício. Espero descobrir que há uma razão pela qual devo continuar dando uma chance.
@ Jonathan Mitchem: C # realmente não se parece com uma linguagem FP, mesmo que a linguagem possua alguns recursos de suporte e algumas bibliotecas possam usá-las. Se você deseja fazer a programação FP no ecossistema da Microsoft, o F # pode ser adequado para você.
@Rainer Não, ele não se parece com uma linguagem FP, mas pode fazê-lo e de maneira bastante compacta. E quando eu quero / preciso de código imperativo ou OO, também posso fazer isso. (um pouco fora do tópico: eu realmente não considero o F # uma linguagem séria que vale a pena investigar, prefiro mexer em mônadas em Haskell. Mas quando eu era um desenvolvedor de C ++ e o C # foi lançado, não o considerei uma linguagem "real" quer [e naquela época não era, imho])
@ Jonathan Mitchem: por que devo procurar? Eu escrevi que o C # suporta alguns recursos de FP. Ele acabou de ser adicionado a uma linguagem imperativa orientada a objetos e não a torna idiomática, como, digamos, Lisp, Scheme e, especialmente, não comparada com SML, F #, Haskell ou outras linguagens principalmente funcionais. Meu argumento é: algum FP é possível em C #, mas não é um recurso essencial.
5

Rainier Joswig disse o melhor.

Para mim, o poder do Lisp não pode ser entendido apenas olhando uma lista de recursos do Lisp. Para Lisp, e Common Lisp em particular, o todo é maior que a soma das partes. Não são apenas as expressões REPL mais s, macros, despacho de vários métodos, fechamentos, pacotes, CLOS e reinicializações, X, Y e Z. É tudo o que há de engenhosamente integrado. É a experiência do dia a dia que é muito, muito diferente da experiência do dia a dia de outras linguagens de programação.

O Lisp parece diferente, é usado de maneira diferente, aborda-se a programação de uma maneira diferente ao usá-lo. É elegante, completo, grande e sem costura. Não é sem suas próprias manchas e pecadilhos. Certamente, há comparações com outros idiomas que podem ser feitas onde talvez não saiam à frente. Mas de maneira alguma o Lisp é apenas o idioma X mais REPL e macros, ou o idioma Y mais o despacho de vários métodos e reinicia.


fonte
3
Código é dados (e macros) - Talvez eu não tenha "recebido" macros, mas não vi um único exemplo em que a idéia de uma macro não pudesse ser implementada como uma função; isso não muda a "linguagem", mas não tenho certeza se isso é uma força

Normalmente, uma macro deve ser usada para algo que não é expressável como uma chamada de função. Não sei se existe um condicional do tipo switch em C # (semelhante ao que existe em C, como switch (form) {case ...}), mas vamos assumir que existe e tem quase as mesmas restrições ( exigindo um tipo integral).

Agora, vamos supor que você gostaria de algo parecido com isso, mas despacha em strings. No lisp (bem, especificamente no Common Lisp e provavelmente em outros), isso é "apenas" uma macro de distância e, se você restringir o usuário a ter strings constantes (provavelmente não árduas) para comparar, poderá calcular (em tempo de compilação) uma sequência mínima de testes para determinar qual caso corresponde (ou usar uma tabela de hash, armazenar fechamentos, talvez).

Embora seja possível expressar isso como uma função (sequência de comparação, uma lista de casos e fechamentos a serem executados), provavelmente não pareceria "código normal" e é aí que as macros lisp têm uma vitória definitiva. Você provavelmente já usou algumas macros ou formas especiais taht são macro-like, como defun, defmacro, setf, cond, loope muitos mais.

Vatine
fonte
2

Este é o melhor artigo explicativo que descobri que leva o leitor da superfície da defesa do Lisp para mostrar algumas das implicações mais profundas dos conceitos que estão sendo usados:

http://www.defmacro.org/ramblings/lisp.html

Lembro-me de ter lido em outro lugar uma idéia como esta: Outras línguas adotaram vários recursos do Lisp; coleta de lixo, digitação dinâmica, funções anônimas, fechamentos para produzir um melhor C ++ / C / Algol. No entanto, para obter todo o poder do Lisp, você precisa de todos os seus recursos essenciais; nesse momento, você tem outro dialeto do Lisp, uma família distinta de idiomas que existe de uma forma ou de outra há mais de 50 anos.

espaço
fonte