Linguagens de programação com um mecanismo de extensão de sintaxe do tipo Lisp [fechado]


20

Eu tenho apenas um conhecimento limitado do Lisp (tentando aprender um pouco no meu tempo livre), mas até onde eu entendo, as macros do Lisp permitem introduzir novas construções de linguagem e sintaxe, descrevendo-as no próprio Lisp. Isso significa que uma nova construção pode ser adicionada como uma biblioteca, sem alterar o compilador / interpretador Lisp.

Essa abordagem é muito diferente da de outras linguagens de programação. Por exemplo, se eu quisesse estender o Pascal com um novo tipo de loop ou algum idioma específico, teria que estender a sintaxe e a semântica da linguagem e, em seguida, implementar esse novo recurso no compilador.

Existem outras linguagens de programação fora da família Lisp (ou seja, além de Common Lisp, Scheme, Clojure (?), Racket (?), Etc) que oferecem uma possibilidade semelhante de estender a linguagem dentro da própria linguagem?

EDITAR

Por favor, evite discussões prolongadas e seja específico em suas respostas. Em vez de uma longa lista de linguagens de programação que podem ser estendidas de uma maneira ou de outra, gostaria de entender, de um ponto de vista conceitual, o que é específico das macros Lisp como um mecanismo de extensão e quais linguagens de programação não-Lisp oferecem algum conceito isso é perto deles.


6
O Lisp tem outro truque além das macros regulares. As "Macros do leitor" permitem que a sintaxe do analisador seja capturada e estendida em tempo de execução, de modo que até a estrutura básica de tokens do idioma está sob controle.
Ddyer 12/09/12

@ ddyer: Obrigado, eu não sabia disso: outro tópico a ser adicionado à minha lista de leitura.
Giorgio

Aposto que a metaprogramação do Ruby pode atender a isso.
Rig

1
sua pergunta é contraditória, primeiro você pede uma lista e depois pede informações conceituais, qual é ???

Estou pedindo uma lista, mas não uma genérica (não apenas qualquer linguagem de programação que possa ser estendida de alguma forma) porque isso seria muito geral. Gostaria de saber sobre idiomas que podem ser estendidos de maneira semelhante ao Lisp (a extensão é definida usando o mesmo idioma que se estende, não algum tipo de meta-linguagem). As respostas de Péter Török, Thomas Eding, SK-logic e Mechanical snail parecem ser as mais próximas do que eu tinha em mente. Ainda tenho que ler todas as respostas cuidadosamente.
Giorgio

Respostas:


19

O Scala também torna isso possível (na verdade, ele foi projetado conscientemente para suportar a definição de novas construções de linguagem e até DSLs completas).

Além das funções de ordem superior, lambdas e currying, que são comuns em linguagens funcionais, existem alguns recursos especiais de linguagem aqui para ativar isso *:

  • sem operadores - tudo é uma função, mas os nomes das funções podem incluir caracteres especiais como '+', '-' ou ':'
  • pontos e chaves podem ser omitidos para chamadas de método de parâmetro único, ou seja, a.and(b)é equivalente a um a and binfixo
  • para chamadas de função de parâmetro único, você pode usar colchetes em vez de chaves normais - isso (junto com o curry) permite escrever coisas como

    val file = new File("example.txt")
    
    withPrintWriter(file) {
      writer => writer.println("this line is a function call parameter")
    }
    

    onde withPrintWriteré um método simples com duas listas de parâmetros, ambas contendo um único parâmetro

  • Os parâmetros por nome permitem omitir a lista de parâmetros vazia em lambdas, permitindo gravar chamadas como myAssert(() => x > 3)em um formato mais curto, comomyAssert(x > 3)

A criação de um exemplo de DSL é discutida em detalhes no Capítulo 11. Idiomas específicos de domínio no Scala do livro gratuito Programming Scala .

* Não quero dizer que sejam exclusivos do Scala, mas pelo menos não parecem ser muito comuns. Eu não sou especialista em linguagens funcionais.


1
+1: Interessante. Isso significa que, para estender a sintaxe, posso definir novas classes e que as assinaturas de método fornecerão a nova sintaxe como subproduto?
Giorgio

@ Giorgio, basicamente sim.
Péter Török

Os links não funcionam mais.
Nate Glenn

13

O Perl permite o pré-processamento de seu idioma. Embora isso não seja frequentemente usado para alterar radicalmente a sintaxe no idioma, ele pode ser visto em alguns dos ... módulos ímpares:

  • Acme :: Bleach para um código realmente limpo
  • Acme :: Morse para escrever em código morse
  • Lingua :: Romana :: Perligata para escrever em latim (por exemplo, os substantivos são variáveis ​​e número, caso e declinação alteram o tipo do substantivo nextum ==> $ next, nexta ==> @next)

Também existe um módulo que permite ao perl executar código que parece ter sido escrito em Python.

Uma abordagem mais moderna para isso no perl seria usar Filter :: Simple (um dos módulos principais do perl5).

Observe que todos esses exemplos envolvem Damian Conway, conhecido como "Mad Doctor of Perl". Ainda é uma capacidade incrivelmente poderosa dentro do perl de distorcer a linguagem da maneira que se deseja.

Mais documentação para esta e outras alternativas existe no perlfilter .


13

Haskell

Haskell tem "Template Haskell" e "Quasiquotation":

http://www.haskell.org/haskellwiki/Template_Haskell

http://www.haskell.org/haskellwiki/Quasiquotation

Esses recursos permitem que os usuários aumentem drasticamente a sintaxe do idioma fora dos meios normais. Eles também são resolvidos no momento da compilação, o que eu acho que é uma grande obrigação (pelo menos para as linguagens compiladas) [1].

Eu usei a quasiquotação no Haskell uma vez antes para criar um comparador de padrões avançado em uma linguagem do tipo C:

moveSegment :: [Token] -> Maybe (SegPath, SegPath, [Token])
moveSegment [hc| HC_Move_Segment(@s, @s); | s1 s2 ts |] = Just (mkPath s1, mkPath s2, ts)
moveSegment _ = Nothing

[1] Caso contrário, o seguinte se qualifica como extensão de sintaxe:, o runFeature "some complicated grammar enclosed in a string to be evaluated at runtime"que obviamente é um monte de porcaria.


3
Existem também outros recursos do Haskell que permitem essencialmente sintaxe personalizada, como criar seu próprio operador ou o currying automático juntamente com funções lambda (considere, por exemplo, o uso típico de forM).
Xion

Sinceramente, acho que os operadores de currying e personalizados não se qualificam. Eles permitem que você use o idioma corretamente, mas não permitem que você adicione / novo / funcionalidade ao idioma. TH e QQ fazem. Em sentido estrito, o TH e o QQ também não fazem no sentido em que fazem exatamente o que foram projetados para fazer, mas permitem que você realmente "saia do idioma" no momento da compilação.
Thomas Eding

1
"Caso contrário, o seguinte se qualifica como extensão de sintaxe ...": ponto muito bom.
Giorgio

12

Tcl tem um longo histórico de suporte à sintaxe extensível. Por exemplo, aqui está a implementação de um loop que itera três variáveis ​​(até parar) sobre os cardeais, seus quadrados e cubos:

proc loopCard23 {cardinalVar squareVar cubeVar body} {
    upvar 1 $cardinalVar cardinal $squareVar square $cubeVar cube

    # We borrow a 'for' loop for the implementation...
    for {set cardinal 0} true {incr cardinal} {
        set square [expr {$cardinal ** 2}]
        set cube [expr {$cardinal ** 3}]

        uplevel 1 $body
    }
}

Isso seria usado assim:

loopCard23 a b c {
    puts "got triplet: $a, $b, $c"
    if {$c > 400} {
        break
    }
}

Esse tipo de técnica é amplamente utilizada na programação Tcl, e a chave para fazê-lo de forma sadia é os comandos upvare uplevel( upvarliga uma variável nomeada em outro escopo a uma variável local e uplevelexecuta um script em outro escopo: nos dois casos, 1indica que o escopo em questão é do chamador). Também é usado muito em código que combina com bancos de dados (executando algum código para cada linha em um conjunto de resultados), em Tk para GUIs (para vincular retornos de chamada a eventos), etc.

No entanto, isso é apenas uma fração do que é feito. A linguagem incorporada nem precisa ser Tcl; pode ser praticamente qualquer coisa (contanto que equilibre seus aparelhos - as coisas ficam sintaticamente horríveis, se isso não for verdade - que é a enorme maioria dos programas) e o Tcl pode apenas enviar para a língua estrangeira incorporada, conforme necessário. Exemplos disso incluem incorporar C para implementar comandos Tcl e o equivalente ao Fortran. (Indiscutivelmente, todos os comandos internos do Tcl são feitos dessa maneira em certo sentido, na medida em que são realmente apenas uma biblioteca padrão e não a própria linguagem.)


10

Isso é parcialmente uma questão de semântica. A idéia básica do Lisp é que o programa seja um dado que possa ser manipulado. Os idiomas comumente usados ​​na família Lisp, como o Scheme, não permitem adicionar novos sintaxe no sentido do analisador; são apenas listas entre parênteses, delimitadas por espaço. Só que, como a sintaxe principal faz tão pouco, é possível criar praticamente qualquer construção semântica . Scala (discutido abaixo) é semelhante: as regras de nome de variável são tão liberais que você pode facilmente criar DSLs agradáveis ​​(mantendo-se dentro das mesmas regras de sintaxe principal).

Essas linguagens, embora não permitam definir uma nova sintaxe no sentido de filtros Perl, têm um núcleo suficientemente flexível que você pode usá-lo para criar DSLs e adicionar construções de linguagem.

O recurso comum importante é que eles permitem definir construções de linguagem que funcionam tão bem quanto as incorporadas, usando recursos expostos pelas linguagens. O grau de suporte para esse recurso varia:

  • Muitos idiomas mais antigos forneciam funções internas como sin(),round() , etc., sem qualquer forma de implementar o seu próprio.
  • C ++ fornece suporte limitado. Por exemplo, alguns built-in palavras-chave como moldes ( static_cast<target_type>(input), dynamic_cast<>(), const_cast<>(), reinterpret_cast<>()) pode ser emulado usando as funções de modelo, que usa impulso para lexical_cast<>(), polymorphic_cast<>(),any_cast<>() , ....
  • Java foi construído com estruturas de controle ( for(;;){}, while(){}, if(){}else{}, do{}while(), synchronized(){}, strictfp{}) e não permitem definir o seu próprio. Em vez disso, Scala define uma sintaxe abstrata que permite chamar funções usando uma sintaxe conveniente da estrutura de controle, e as bibliotecas usam isso para definir efetivamente novas estruturas de controle (por exemplo, react{}na biblioteca de atores).

Além disso, você pode examinar a funcionalidade de sintaxe personalizada do Mathematica no pacote Notação . (Tecnicamente, ele está na família Lisp, mas possui alguns recursos de extensibilidade feitos de maneira diferente, bem como a extensibilidade usual do Lisp.)


2
Errado. O Lisp permite realmente adicionar qualquer tipo de nova sintaxe. Como neste exemplo: meta-alternative.net/pfront.pdf - nada mais é do que uma macro Lisp.
SK-logic

Isso parece ser implementado em uma linguagem projetada especificamente para a construção de DSLs . Claro que você pode criar um idioma na família Lisp que também ofereça esses recursos; Eu quis dizer que esse recurso não é uma idéia central do Lisp suportada por Lisps usados ​​com frequência (por exemplo, Scheme). Editado para esclarecer.
Caracol mecânico

Essa "linguagem para criar DSLs" é uma coleção de macros criadas sobre um Lisp minimalista e bastante típico. Pode ser facilmente portado para qualquer outro Lisp com (defmacro ...). Atualmente, estou portando esse idioma para o Racket, apenas por diversão. Mas, eu concordo que é algo não muito útil, uma vez que a sintaxe das expressões S é mais que suficiente para a maioria dos possíveis s semânticos úteis.
SK-logic

E, o Scheme não é diferente do Common Lisp, a partir do R6RS oficialmente e não oficialmente por idades, pois fornece um (define-macro ...)equivalente que, por sua vez, pode usar qualquer tipo de análise internamente.
SK-logic

8

Rebol soa quase como o que você está descrevendo, mas um pouco de lado.

Em vez de definir sintaxe específica, tudo no Rebol é uma chamada de função - não há palavras-chave. (Sim, você pode redefinir ife whilese realmente desejar). Por exemplo, esta é uma ifdeclaração:

if now/time < 12:00 [print "Morning"]

ifé uma função que recebe 2 argumentos: uma condição e um bloco. Se a condição for verdadeira, o bloco é avaliado. Parece a maioria das línguas, certo? Bem, o bloco é uma estrutura de dados, não está restrito ao código - este é um bloco de blocos, por exemplo, e um exemplo rápido da flexibilidade de "código é dados":

SomeArray: [ [foo "One"] [bar "Two"] [baz "Three"] ]
foreach action SomeArray [action/1: 'print] ; Change the data
if now/time < 12:00 SomeArray/2 ; Use the data as code - right now, if now/time < 12:00 [print "Two"]

Desde que você possa seguir as regras de sintaxe, estender esse idioma será, na maioria das vezes, nada mais do que definir novas funções. Alguns usuários estão suportando recursos do Rebol 3 no Rebol 2, por exemplo.


7

Ruby tem uma sintaxe bastante flexível, acho que é uma maneira de "estender a linguagem dentro da própria linguagem".

Um exemplo é o rake . Está escrito em Ruby, é Ruby, mas parece make .

Para verificar algumas possibilidades, você pode procurar pelas palavras-chave Ruby e metaprogramação .


13
"sintaxe flexível" é MUITO diferente de "sintaxe extensível". Já faz muito tempo desde que eu programei em Ruby, mas o Rake parece um uso bem projetado da sintaxe interna. Em outras palavras, isso não é um exemplo.
Thomas Eding

2
Isso não é uma questão de grau, não é do tipo? Como você distinguiria uma linguagem de "sintaxe extensível" que pode estender alguns aspectos de sua sintaxe, mas não outros, e uma linguagem de "sintaxe flexível"?
comingstorm

1
Se a linha estiver embaçada, vamos empurrá-la de volta para que C seja considerado como suporte à sintaxe extensível.
Thomas Eding

Para vincular ao seu exemplo, eu traçaria a linha aqui: Uma linguagem com sintaxe extensível pode criar rake, que se parece com make. Uma linguagem com sintaxe flexível pode ser estendida (ha, ótima mistura linguística) para compilar e executar makefiles. Porém, seu ponto de vista sobre o grau é bom. Talvez algumas linguagens permitam compilar o Make, mas não o Python. E outros permitiriam ambos.
Clayton Stanley

Qualquer idioma completo do turing deve poder ser criado para processar arquivos Make. A flexibilidade da sintaxe não é um fator além de quanto seria um desafio.
Rig

7

Estender a sintaxe da maneira como você está falando permite criar idiomas específicos do domínio. Portanto, talvez a maneira mais útil de reformular sua pergunta seja: quais outros idiomas têm um bom suporte para idiomas específicos de domínio?

Ruby tem uma sintaxe muito flexível, e muitas DSLs floresceram lá, como rake. Groovy inclui muito dessa bondade. Ele também inclui transformações AST, que são mais diretamente análogas às macros Lisp.

R, a linguagem para computação estatística, permite que as funções obtenham seus argumentos não avaliados. Ele usa isso para criar uma DSL para especificar a fórmula de regressão. Por exemplo:

y ~ a + b

significa "ajustar uma linha da forma k0 + k1 * a + k2 * b aos valores em y".

y ~ a * b

significa "ajustar uma linha da forma k0 + k1 * a + k2 * b + k3 * a * b aos valores em y".

E assim por diante.


2
As transformações AST do Groovy são muito detalhadas em comparação com as macros Lisp ou Clojure. Por exemplo, o exemplo Groovy com mais de 20 linhas em groovy.codehaus.org/Global+AST+Transformations pode ser reescrito como uma linha curta no Clojure, por exemplo, `(this (println ~ message)). Não apenas isso, mas você também não precisaria compilar o jar, escrever os metadados ou qualquer outra coisa nessa página do Groovy.
Vorg van Geir

7

Converge é outra linguagem de metaprogramação não lispy. E, até certo ponto, o C ++ também se qualifica.

Indiscutivelmente, o MetaOCaml está bem longe do Lisp. Para um estilo totalmente diferente de extensibilidade de sintaxe, mas ainda bastante poderoso, dê uma olhada no CamlP4 .

Nemerle é outra linguagem extensível com uma metaprogramação no estilo Lisp, embora seja mais próxima de linguagens como Scala.

E, em breve , o próprio Scala também se tornará uma linguagem desse tipo.

Edit: Eu esqueci o exemplo mais interessante - JetBrains MPS . Ele não é apenas muito distante de qualquer coisa do Lispish, é também um sistema de programação não textual, com um editor operando diretamente no nível AST.

Edit2: Para responder a uma pergunta atualizada - não há nada de único e excepcional nas macros do Lisp. Em teoria, qualquer linguagem pode fornecer esse mecanismo (eu até fiz isso com C simples). Tudo o que você precisa é de acesso ao seu AST e capacidade de executar código em tempo de compilação. Alguma reflexão pode ajudar (consultar sobre os tipos, as definições existentes etc.).


Seu link do Scala diz explicitamente que as macros propostas "não podem alterar a sintaxe do Scala". (Interessante, ele lista como uma diferença entre esta proposta e C / C ++ pré-processador macros!)
ruach

@ruakh, sim, é a mesma abordagem que Converge e Template Haskell - o aplicativo macro é explicitamente marcado e não pode ser misturado com uma sintaxe "normal". Mas, por dentro, você pode ter qualquer sintaxe que desejar, então, sem dúvida, é uma sintaxe extensível. O requisito "non-lisp", infelizmente, limita suas opções a idiomas como este.
SK-logic

"Eu até fiz isso com C simples": como isso é possível?
Giorgio

@Giorgio, é claro que eu modifiquei um compilador (macros adicionadas e uma compilação de módulo incremental, que é realmente natural para C).
SK-logic

Por que o acesso ao AST é necessário?
Elliot Gorokhovsky,

6

O Prolog permite definir novos operadores que são traduzidos para termos compostos com o mesmo nome. Por exemplo, isso define um has_catoperador e o define como um predicado para verificar se uma lista contém o átomo cat:

:- op(500, xf, has_cat).
X has_cat :- member(cat, X).

?- [apple, cat, orange] has_cat.
true ;
false.

O xfmeio que has_caté um operador postfix; usando fxo tornaria um operador de prefixo e xfxo tornaria um operador de infixo, recebendo dois argumentos. Verifique este link para obter mais detalhes sobre a definição de operadores no Prolog.


5

O TeX está totalmente ausente da lista. Vocês todos sabem, certo? Parece algo como isto:

Some {\it ``interesting''} example.

… Exceto que você pode redefinir a sintaxe sem restrições. Cada token (!) No idioma pode receber um novo significado. O ConTeXt é um pacote de macro que substituiu os chavetas por chavetas:

Some \it[``interesting''] example.

O pacote macro mais comum LaTeX também redefine o idioma para seus fins, por exemplo, adicionando o\begin{environment}…\end{environment} sintaxe.

Mas não para por aí. Tecnicamente, você também pode redefinir os tokens para analisar o seguinte:

Some <it>“interesting”</it> example.

Sim, absolutamente possível. Alguns pacotes usam isso para definir pequenos idiomas específicos do domínio. Por exemplo, o pacote TikZ define uma sintaxe concisa para desenhos técnicos, que permite o seguinte:

\foreach \angle in {0, 30, ..., 330} 
  \draw[line width=1pt] (\angle:0.82cm) -- (\angle:1cm);

Além disso, o TeX é o Turing completo para que você possa literalmente fazer tudo com ele. Eu nunca vi isso usado em todo o seu potencial, porque seria muito inútil e muito complicado, mas é perfeitamente possível tornar o código a seguir analisável apenas redefinindo os tokens (mas isso provavelmente iria para os limites físicos do analisador, devido ao como é construído):

for word in [Some interesting example.]:
    if word == interesting:
        it(word)
    else:
        word

5

O Boo permite que você personalize o idioma intensamente em tempo de compilação por meio de macros sintáticas.

O Boo tem um "pipeline de compilador extensível". Isso significa que o compilador pode chamar seu código para fazer transformações AST a qualquer momento durante o pipeline do compilador. Como você sabe, coisas como Genéricos do Java ou Linq do C # são apenas transformações de sintaxe em tempo de compilação, portanto isso é bastante poderoso.

Comparado ao Lisp, a principal vantagem é que isso funciona com qualquer tipo de sintaxe. O Boo está usando uma sintaxe inspirada em Python, mas você provavelmente poderia escrever um compilador extensível com uma sintaxe C ou Pascal. E como a macro é avaliada em tempo de compilação, não há penalidade no desempenho.

As desvantagens, em comparação com o Lisp, são:

  • Trabalhar com um AST não é tão elegante quanto trabalhar com expressões s
  • Como a macro é chamada em tempo de compilação, ela não tem acesso aos dados de tempo de execução.

Por exemplo, é assim que você pode implementar uma nova estrutura de controle:

macro repeatLines(repeatCount as int, lines as string*):
    for line in lines:
        yield [| print $line * $repeatCount |]

uso:

repeatLines 2, "foo", "bar"

que é traduzido, em tempo de compilação, para algo como:

print "foo" * 2
print "bar" * 2

(Infelizmente, a documentação on-line do Boo está sempre irremediavelmente desatualizada e nem cobre itens avançados como este. A melhor documentação para o idioma que conheço é este livro: http://www.manning.com/rahien/ )


1
A documentação da Web para esse recurso está quebrada no momento e eu não escrevo o Boo, mas achei que seria uma pena se fosse ignorado. Agradeço o feedback do mod e reconsidere como contribuirei com informações gratuitas no meu tempo livre.
Dan

4

A avaliação do Mathematica é baseada na correspondência e substituição de padrões. Isso permite criar suas próprias estruturas de controle, alterar estruturas de controle existentes ou alterar a maneira como as expressões são avaliadas. Por exemplo, você pode implementar "lógica difusa" assim (um pouco simplificada):

fuzzy[a_ && b_]      := Min[fuzzy[a], fuzzy[b]]
fuzzy[a_ || b_]      := Max[fuzzy[a], fuzzy[b]]
fuzzy[!a_]           := 1-fuzzy[a]
If[fuzzy[a_], b_,c_] := fuzzy[a] * fuzzy[b] + fuzzy[!a] * fuzzy[c]

Isso substitui a avaliação dos operadores lógicos predefinidos &&, || ,! e a Ifcláusula incorporada .

Você pode ler essas definições como definições de função, mas o significado real é: Se uma expressão corresponder ao padrão descrito no lado esquerdo, ela será substituída pela expressão no lado direito. Você pode definir sua própria cláusula If como esta:

myIf[True, then_, else_] := then
myIf[False, then_, else_] := else
SetAttributes[myIf, HoldRest]

SetAttributes[..., HoldRest] informa ao avaliador que ele deve avaliar o primeiro argumento antes da correspondência do padrão, mas mantenha a avaliação pelo resto até depois que o padrão for correspondido e substituído.

Isso é amplamente utilizado nas bibliotecas padrão do Mathematica para, por exemplo, definir uma função Dque pega uma expressão e avalia sua derivada simbólica.


3

O Metalua é uma linguagem e um compilador compatível com Lua que fornece isso.

  • Compatibilidade total com fontes e código de lua Lua 5.1: semântica e sintaxe limpas e elegantes, poder expressivo incrível, bons desempenhos, portabilidade quase universal. - Um sistema macro completo, semelhante em poder ao que é oferecido pelos dialetos Lisp ou Template Haskell; programas manipulados podem ser vistos
    como código fonte, como árvores de sintaxe abstratas ou como uma mistura arbitrária dos
    mesmos, o que melhor se adequar à sua tarefa.
  • Um analisador dinamicamente extensível, que permite que você ofereça suporte às suas macros com uma sintaxe que combina muito bem com o restante do idioma.

  • Um conjunto de extensões de idioma, todas implementadas como macros metalua regulares.

Diferenças com o Lisp:

  • Não incomode os desenvolvedores com macros quando não estiverem escrevendo uma: a sintaxe e a semântica da linguagem devem ser mais adequadas para aqueles 95% das vezes em que não estamos escrevendo macros.
  • Incentive os desenvolvedores a seguir as convenções do idioma: não apenas com as "melhores práticas" que ninguém escuta, mas oferecendo uma API que facilita a escrita das coisas da maneira Metalua. A legibilidade de outros desenvolvedores é mais importante e mais difícil de alcançar do que a legibilidade dos compiladores e, para isso, ter um conjunto comum de convenções respeitadas ajuda muito.
  • No entanto, forneça todo o poder que alguém deseja controlar. Nem Lua nem Metalua são escravos e disciplinares obrigatórios; portanto, se você souber o que está fazendo, o idioma não ficará no seu caminho.
  • Torne óbvio quando algo interessante acontecer: todas as meta-operações acontecem entre + {...} e - {...} e permanecem visualmente fora do código normal.

Um exemplo de aplicação é a implementação da correspondência de padrões do tipo ML.

Veja também: http://lua-users.org/wiki/MetaLua


Embora Lua não seja realmente um Lisp, sua lista de "diferenças" é bastante suspeita (o único item relevante é o último). E, é claro, a comunidade Lisp não concordaria com um discurso retórico de que não se deve escrever / usar macros 95% das vezes - a maneira Lisp se inclina para algo como 95% do tempo usando e escrevendo DSLs, em cima de macros, de curso.
SK-logic

2

Se você está procurando idiomas extensíveis, deve dar uma olhada no Smalltalk.

No Smalltalk, a única maneira de programar é realmente estender o idioma. Não há diferença entre o IDE, as bibliotecas ou a própria linguagem. Eles estão todos tão entrelaçados que o Smalltalk é frequentemente referido como um ambiente e não como um idioma.

Você não escreve aplicativos independentes no Smalltalk; em vez disso, estende o ambiente de linguagem.

Confira http://www.world.st/ para obter alguns recursos e informações.

Eu gostaria de recomendar o Pharo como o dialeto de entrada no mundo do Smalltalk: http://pharo-project.org

Espero que tenha ajudado!


1
Soa interessante.
Thomas Eding

1

Existem ferramentas que permitem criar linguagens personalizadas sem escrever um compilador inteiro do zero. Por exemplo, há Spoofax , que é uma ferramenta de transformação de código: você coloca regras de gramática e transformação de entrada (escritas de maneira declarativa de nível muito alto) e, em seguida, pode gerar o código-fonte Java (ou outra linguagem, se você se interessar o suficiente) de um idioma personalizado criado por você.

Portanto, seria possível pegar a gramática da linguagem X, definir a gramática da linguagem X '(X com suas extensões personalizadas) e transformar X' → X, e o Spoofax gerará um compilador X '→ X.

Atualmente, se eu entendi direito, o melhor suporte é para Java, com o suporte a C # sendo desenvolvido (ou pelo menos ouvi dizer). Essa técnica pode ser aplicada a qualquer idioma com gramática estática (portanto, por exemplo, provavelmente não Perl ).


1

Quarto é outro idioma que é altamente extensível. Muitas implementações do Forth consistem em um pequeno kernel escrito em assembler ou C, e o restante do idioma é escrito no próprio Forth.

Existem também vários idiomas baseados em pilha que são inspirados pelo Forth e compartilham esse recurso, como o Factor .


0

Funge-98

O recurso de impressão digital do Funge-98 permite que possa ser feito para permitir uma reestruturação completa de toda a sintaxe e semântica da linguagem. Mas somente se o implementador fornecer um mecanismo de impressão digital que permita ao usuário alterar programaticamente o idioma (isso é teoricamente possível de implementar na sintaxe e na semântica normais do Funge-98). Nesse caso, alguém poderia literalmente fazer com que o restante do arquivo (ou qualquer parte do arquivo) aja como C ++ ou Lisp (ou o que ele quiser).

http://quadium.net/funge/spec98.html#Fingerprints


por que você publicou isso separadamente em vez de adicionar à sua resposta anterior ?
gnat

1
Porque Funge não tem nada a ver com Haskell.
Thomas Eding

-1

Para obter o que você está procurando, você realmente precisa desses parênteses e falta de sintaxe. Algumas linguagens baseadas em sintaxe podem se aproximar, mas não é exatamente a mesma coisa que uma macro verdadeira.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.