Em que área a macro do LISP é melhor do que a “capacidade” de Ruby de criar DSL

21

Uma das coisas que faz Ruby brilhar é a capacidade de criar melhor idiomas específicos de domínio, como

Embora se possa duplicar essas bibliotecas no LISP por meio de macro, acho que a implementação do Ruby é mais elegante. No entanto, acho que há casos em que a macro do LISP pode ser melhor que a do Ruby, embora eu não pudesse pensar em um.

Então, em que área a macro do LISP é melhor do que a "capacidade" de Ruby de criar DSL, se houver?

atualizar

Eu perguntei isso porque as linguagens de programação modernas estão se aproximando da singularidade do LISP , como

  • C obteve pré-processador de expansão macro , embora muito primitivo e propenso a erros
  • C # tem atributos, embora seja somente leitura, exposto por reflexão
  • O Python adicionou o decorador, que pode modificar o comportamento da função (e classe para a v 3.0), embora pareça bastante limitado.
  • Ruby TMTOWTDI que cria DSL elegante, se o cuidado for aplicado, mas de maneira Ruby.

Fiquei pensando se a macro do LISP é aplicável apenas a casos especiais e se os outros recursos da linguagem de programação são poderosos o suficiente para aumentar a abstração para enfrentar os desafios atuais do desenvolvimento de software.

OnesimusUnbound
fonte
4
Não sei ao certo por que há votos íntimos nisso. Eu acho que esse é o tipo de pergunta que queremos ? Interessante, instigante e o escopo é definido muito bem.
Tim Post
Tente implementar algo parecido com isto em Ruby: meta-alternative.net/pfront.pdf
SK-logic
@ Tim Post: Um problema é que isso realmente não é uma pergunta fácil de responder, a menos que você conheça bem Common Lisp e Ruby. Outra são as referências bastante ignorantes a outras linguagens, o que pode incomodar os puristas: não existe uma linguagem chamada C / C ++, e a parte significativa do C ++ é o sistema de modelos, e a sugestão de que o sistema macro do Common Lisp seja aplicável apenas a casos especiais. Fundamentalmente, é uma boa pergunta, mas está mal escrita e difícil de responder.
precisa
@ David Thornley, atualizei o post, principalmente em C \ C ++, e coloquei ênfase em C. Quanto ao Common Lisp, senti que, como outras linguagens de programação têm maior abstração, seu recurso de macro é um caso especial. Postei a pergunta, esperando que outras pessoas me mostrassem que a macro da CL não é um caso especial ainda é um recurso poderoso.
carregar a caixa de mensagens
@OnesimusUnbound: Eu realmente incluiria os modelos de C ++ na sua lista de exemplos de linguagem, pois eles são pelo menos teoricamente capazes de qualquer cálculo que o sistema de macro Lisp possa fazer. No que diz respeito às macros do Lisp, obtenha um bom código Common Lisp (existe bastante código Lis / F / OS) e procure por "defmacro" (você pode fazer uma pesquisa que não diferencia maiúsculas de minúsculas). Você provavelmente encontrará muitos deles. Considere que as macros são mais difíceis do que as funções de escrever e acertar, e você perceberá que elas geralmente precisam ser úteis.
precisa

Respostas:

23

Leia No Lisp e decida por si mesmo.

Meu resumo é que Ruby é melhor em fornecer sintaxe conveniente. Mas Lisp vence, sem dúvida, a capacidade de criar novas abstrações e, em seguida, colocar a abstração em camadas. Mas você precisa ver o Lisp na prática para entender esse ponto. Daí o livro recomendar.

btilly
fonte
1
"Let Over Lambda" cobre um terreno muito semelhante. Leitura também recomendada.
John R. Strohm
But Lisp wins, hands down, at the ability to create new abstractions, and then to layer abstraction on abstraction.Agora eu sei o porquê. . .
carregar a caixa de mensagens
Não é grande coisa fornecer qualquer tipo de sintaxe sobre o Lisp. De fato, muito mais fácil do que com Ruby, graças às macros do leitor.
SK-logic
1
@ SK-logic: Verdadeiro. No entanto, os Lispers evitam as macros do leitor, porque uma vez que você segue esse caminho, ele não se parece mais com um Lisp. De fato, algumas variantes do Lisp, como o Clojure, reservam macros de leitor para o designer de idiomas.
btilly
14

As instalações do Ruby para criação de DSL não mudam a natureza do idioma. As instalações de metaprogramação do Ruby estão inerentemente ligadas à sintaxe e à semântica do Ruby, e o que quer que você escreva deve ser desviado para o modelo de objeto do Ruby.

Compare isso com Lisp (e Scheme, cujas macros são diferentes ), onde as macros operam no próprio programa abstrato. Como um programa Lisp é um valor Lisp, uma macro é uma função que mapeia uma sintaxe essencialmente arbitrária para outra.

Efetivamente, um DSL Ruby ainda se parece com Ruby, mas um DSL Lisp não precisa se sentir como Lisp.

Jon Purdy
fonte
6
+1: LOOP não parece muito Lispy, como um exemplo de DSL.
Frank Shearar
2

Os DSLs de Ruby não são DSLs, e eu absolutamente odeio usá-los porque a documentação deles é sobre como eles realmente funcionam. Vamos pegar o ActiveRecord, por exemplo. Permite "declarar" associações entre modelos:

class Foo < ActiveRecord::Base
    has_one :bar
    has_one :baz
end

Mas a declaratividade desse "DSL" (como a classprópria sintaxe do Ruby ) é uma mentira horrível que pode ser exposta por qualquer pessoa que entenda como o "DSLs" do Ruby realmente funciona:

class Foo < ActiveRecord::Base
    [:bar,:baz,:qux,:quux].each do |table|
        has_one table if i_feel_like_it?(table)
    end
    puts "Just for shits and giggles, and to show"
    puts "just how fucked up Ruby really is, we're gonna ask you"
    puts "which SQL table you want the Foo model to have an"
    puts "association with.\n"
    puts "Type the name of a table here: "
    has_one gets.chomp.to_sym
end

(Tente fazer algo parecido com isso no corpo de um defclassformulário Lisp !)

Assim que você tem um código como o acima em sua base de código, todo desenvolvedor do projeto precisa entender completamente como DSLs do Ruby realmente funcionam (não apenas a ilusão que eles criam) antes de poderem manter o código. A documentação disponível será completamente inútil, porque documentam apenas o uso idiomático , o que preserva a ilusão declarativa.

O RSpec é ainda pior do que o acima, porque possui casos extremos bizarros que exigem extensa engenharia reversa para depuração. (Passei um dia inteiro tentando descobrir por que um dos meus casos de teste estava sendo ignorado. Verificou-se que o RSpec executa todos os casos de teste que têm contextos após casos de teste sem contexto, independentemente da ordem em que aparecem na origem , porque o contextmétodo coloca seu bloco em uma estrutura de dados diferente da que normalmente seria inserida.)

As DSLs do Lisp são implementadas por macros, que são pequenos compiladores. As DSLs que você pode criar dessa maneira não são meros abusos da sintaxe existente do Lisp. Eles são mini-idiomas reais que podem ser escritos para serem completamente perfeitos, porque podem ter sua própria gramática. Por exemplo, a LOOPmacro do Lisp é muito mais poderosa que o eachmétodo Ruby .

(Eu sei que você já aceitou uma resposta, mas nem todo mundo que lê isso quer ler a totalidade do On Lisp .)

Jogue fora a conta
fonte