Lenguajes de programación con un mecanismo de extensión de sintaxis tipo Lisp [cerrado]

20

Solo tengo un conocimiento limitado de Lisp (tratando de aprender un poco en mi tiempo libre), pero hasta donde entiendo, las macros de Lisp permiten introducir nuevas construcciones y sintaxis del lenguaje describiéndolas en Lisp. Esto significa que se puede agregar una nueva construcción como una biblioteca, sin cambiar el compilador / intérprete Lisp.

Este enfoque es muy diferente al de otros lenguajes de programación. Por ejemplo, si quisiera extender Pascal con un nuevo tipo de bucle o algún idioma en particular, tendría que extender la sintaxis y la semántica del lenguaje y luego implementar esa nueva característica en el compilador.

¿Existen otros lenguajes de programación fuera de la familia Lisp (es decir, aparte de Common Lisp, Scheme, Clojure (?), Racket (?), Etc.) que ofrecen una posibilidad similar de extender el lenguaje dentro del lenguaje mismo?

EDITAR

Por favor, evite discusiones extensas y sea específico en sus respuestas. En lugar de una larga lista de lenguajes de programación que pueden ampliarse de una forma u otra, me gustaría entender desde un punto de vista conceptual qué es específico de las macros Lisp como mecanismo de extensión y qué lenguajes de programación que no son de Lisp ofrecen algún concepto. eso está cerca de ellos.

Giorgio
fuente
66
Lisp tiene otro truco además de las macros normales. Las "Macros de lector" permiten capturar y extender la sintaxis del analizador en tiempo de ejecución, por lo que incluso la estructura de token básica del lenguaje está bajo control.
ddyer
@ddyer: Gracias, no sabía sobre eso: otro tema para agregar a mi lista de lectura.
Giorgio
Apuesto a que la metaprogramación de Ruby puede cumplir con esto.
Plataforma
1
tu pregunta es contradictoria, primero pides una lista, luego pides información conceptual, ¿cuál es?
Estoy pidiendo una lista, pero no una genérica (no cualquier lenguaje de programación que pueda extenderse de alguna manera) porque esto sería demasiado general. Me gustaría saber de lenguajes que se puedan extender de manera similar a Lisp (la extensión se define usando el mismo lenguaje que se extiende, no algún tipo de metalenguaje). Las respuestas de Péter Török, Thomas Eding, SK-logic y Mechanical snail parecen ser las más cercanas a lo que tenía en mente. Sin embargo, todavía tengo que leer toda la respuesta cuidadosamente.
Giorgio

Respuestas:

19

Scala también lo hace posible (de hecho, fue diseñado conscientemente para admitir la definición de nuevas construcciones de lenguaje e incluso DSL completas).

Además de las funciones de orden superior, lambdas y curry, que son comunes en los lenguajes funcionales, hay algunas características especiales del lenguaje para habilitar esto *:

  • sin operadores: todo es una función, pero los nombres de las funciones pueden incluir caracteres especiales como '+', '-' o ':'
  • Se pueden omitir puntos y llaves para llamadas a métodos de un solo parámetro, a.and(b)es decir, es equivalente a a and ben forma infija
  • para llamadas a funciones de un solo parámetro, puede usar llaves en lugar de llaves normales; esto (junto con el currículum) le permite escribir cosas como

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

    donde withPrintWriteres un método simple con dos listas de parámetros, ambos contienen un solo parámetro

  • Los parámetros por nombre le permiten omitir una lista de parámetros vacía en lambdas, lo que le permite escribir llamadas como myAssert(() => x > 3)en una forma más corta comomyAssert(x > 3)

La creación de un ejemplo de DSL se trata en detalle en el Capítulo 11. Lenguajes específicos de dominio en Scala del libro gratuito Programming Scala .

* No quiero decir que sean exclusivos de Scala, pero al menos no parecen ser muy comunes. Sin embargo, no soy un experto en lenguajes funcionales.

Péter Török
fuente
1
+1: interesante. ¿Significa esto que para extender la sintaxis puedo definir nuevas clases y que las firmas de métodos proporcionarán la nueva sintaxis como un subproducto?
Giorgio
@ Jorge, básicamente sí.
Péter Török
Los enlaces ya no funcionan.
Nate Glenn
13

Perl permite el preprocesamiento de su lenguaje. Si bien esto no se usa a menudo para cambiar radicalmente la sintaxis en el idioma, se puede ver en algunos de los ... módulos extraños:

  • Acme :: Bleach para un código realmente limpio
  • Acme :: Morse para escribir en código morse
  • Lingua :: Romana :: Perligata para escribir en latín (por ejemplo, los sustantivos son variables y el número, el caso y la declinación cambian el tipo del sustantivo nextum ==> $ next, nexta ==> @next)

También existe un módulo que permite que Perl ejecute código que parece haber sido escrito en Python.

Un enfoque más moderno para esto dentro de perl sería usar Filter :: Simple (uno de los módulos principales en perl5).

Tenga en cuenta que todos esos ejemplos involucran a Damian Conway, a quien se ha referido como el "Doctor loco de Perl". Todavía es una habilidad increíblemente poderosa dentro de Perl para torcer el idioma como uno lo quiere.

Existe más documentación para esta y otras alternativas en perlfilter .

usuario40980
fuente
13

Haskell

Haskell tiene "Template Haskell" y "Cuasiquotation":

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

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

Estas características permiten a los usuarios agregar dramáticamente a la sintaxis del lenguaje fuera de los medios normales. Estos también se resuelven en el momento de la compilación, lo que creo que es una gran necesidad (al menos para los lenguajes compilados) [1].

He usado la cuasiquotación en Haskell una vez antes para crear un emparejador de patrones avanzado sobre un lenguaje 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] De lo contrario, lo siguiente califica como extensión de sintaxis: runFeature "some complicated grammar enclosed in a string to be evaluated at runtime"que, por supuesto, es una carga de basura.

Thomas Eding
fuente
3
También hay otras características de Haskell que esencialmente permiten una sintaxis personalizada, como crear su propio operador o el curry automático junto con funciones lambda (considere, por ejemplo, el uso típico de forM).
Xion
Sinceramente, creo que el currículum y los operadores personalizados no califican. Permiten que uno use el idioma de manera ordenada, pero no le permiten agregar / nuevo / funcionalidad al idioma. TH y QQ lo hacen. En un sentido estricto, tampoco lo hacen TH y QQ en el sentido de que hacen exactamente lo que están diseñados para hacer, pero le permiten realmente "salir del lenguaje" en el momento de la compilación.
Thomas Eding
1
"De lo contrario, lo siguiente califica como extensión de sintaxis ...": muy buen punto.
Giorgio
12

Tcl tiene una larga historia de soporte de sintaxis extensible. Por ejemplo, aquí está la implementación de un ciclo que itera tres variables (hasta que se detiene) sobre los cardenales, sus cuadrados y sus 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
    }
}

Eso se usaría así:

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

Este tipo de técnica se usa ampliamente en la programación de Tcl, y la clave para hacerlo de manera sensata son los comandos upvary uplevel( upvarvincula una variable con nombre en otro ámbito a una variable local y uplevelejecuta un script en otro ámbito: en ambos casos, el 1indica que el alcance en cuestión es la persona que llama). También se usa mucho en el código que se combina con las bases de datos (ejecutando algo de código para cada fila en un conjunto de resultados), en Tk para GUI (para vincular devoluciones de llamada a eventos), etc.

Sin embargo, eso es solo una fracción de lo que se hace. El lenguaje incrustado ni siquiera necesita ser Tcl; puede ser prácticamente cualquier cosa (siempre que equilibre sus llaves, las cosas se vuelven sintácticamente horribles si eso no es cierto, que es la gran mayoría de los programas) y Tcl puede simplemente enviarlo al idioma extranjero incorporado según sea necesario. Ejemplos de esto incluyen incrustar C para implementar comandos Tcl y el equivalente con Fortran. (Podría decirse que todos los comandos integrados de Tcl se realizan de esta manera en cierto sentido, ya que en realidad son solo una biblioteca estándar y no el lenguaje en sí).

Compañeros de Donal
fuente
10

Esto es en parte una cuestión de semántica. La idea básica de Lisp es que el programa son datos que pueden ser manipulados. Los lenguajes de uso común en la familia Lisp, como Scheme, realmente no le permiten agregar una nueva sintaxis en el sentido del analizador sintáctico; todo es solo listas entre paréntesis delimitadas por espacios. Es solo que, dado que la sintaxis central hace muy poco, puedes hacer casi cualquier construcción semántica con ella. Scala (discutido a continuación) es similar: las reglas de nombre de variable son tan liberales que puede hacer fácilmente DSL agradables (mientras se mantiene dentro de las mismas reglas de sintaxis central).

Estos lenguajes, si bien en realidad no le permiten definir una nueva sintaxis en el sentido de los filtros Perl, tienen un núcleo lo suficientemente flexible que puede usar para crear DSL y agregar construcciones de lenguaje.

La característica común importante es que le permiten definir construcciones de lenguaje que funcionan tan bien como las incorporadas, utilizando características expuestas por los idiomas. El grado de soporte para esta característica varía:

  • Muchos lenguajes anteriores, siempre y funciones integradas como sin(), round(), etc., sin ninguna forma de implementar su propio.
  • C ++ proporciona soporte limitado. Por ejemplo, algunos incorporado en palabras clave como moldes ( static_cast<target_type>(input), dynamic_cast<>(), const_cast<>(), reinterpret_cast<>()) se pueden emular el uso de funciones de plantilla, que utiliza para Boost lexical_cast<>(), polymorphic_cast<>(), any_cast<>(), ....
  • Java se ha incorporado en las estructuras de control ( for(;;){}, while(){}, if(){}else{}, do{}while(), synchronized(){}, strictfp{}) y no permitirá definir su propio. En cambio, Scala define una sintaxis abstracta que le permite invocar funciones utilizando una sintaxis similar a la estructura de control conveniente, y las bibliotecas la utilizan para definir efectivamente nuevas estructuras de control (por ejemplo, react{}en la biblioteca de actores).

Además, puede consultar la funcionalidad de sintaxis personalizada de Mathematica en el paquete de notación . (Técnicamente, pertenece a la familia Lisp, pero tiene algunas características de extensibilidad realizadas de manera diferente, así como la extensibilidad habitual de Lisp).

Caracol mecánico
fuente
2
Incorrecto. Lisp hace realidad le permite agregar absolutamente cualquier tipo de una nueva sintaxis. Como en este ejemplo: meta-alternative.net/pfront.pdf : no es más que una macro Lisp.
SK-logic
Eso parece implementarse en un lenguaje específicamente diseñado para construir DSL . Por supuesto, puede crear un idioma en la familia Lisp que también proporcione tales características; Quise decir que esa característica no es una idea central de Lisp compatible con Lisps de uso común (por ejemplo, Scheme). Editado para aclarar.
Caracol mecánico
Este "lenguaje para construir DSL" es una colección de macros construidas sobre un Lisp minimalista bastante típico. Se puede portar fácilmente a cualquier otro Lisp con (defmacro ...). Actualmente estoy portando este lenguaje a Racket, solo por diversión. Pero, estoy de acuerdo en que es algo no muy útil, ya que la sintaxis de expresiones S es más que suficiente para la mayoría de las posibles semánticas útiles.
SK-logic
Y, Scheme no es diferente de Common Lisp, comenzando desde R6RS oficialmente, y no oficialmente durante años, ya que proporciona un (define-macro ...)equivalente, que, a su vez, puede usar cualquier tipo de análisis interno.
SK-logic
8

Rebol suena casi como lo que estás describiendo, pero un poco de lado.

En lugar de definir una sintaxis específica, todo en Rebol es una llamada de función: no hay palabras clave. (Sí, puede redefinir ify whilesi realmente lo desea). Por ejemplo, esta es una ifdeclaración:

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

ifes una función que toma 2 argumentos: una condición y un bloque. Si la condición es verdadera, se evalúa el bloque. Suena como la mayoría de los idiomas, ¿verdad? Bueno, el bloque es una estructura de datos, no está restringido al código; este es un bloque de bloques, por ejemplo, y un ejemplo rápido de la flexibilidad del "código es datos":

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"]

Siempre y cuando pueda apegarse a las reglas de sintaxis, extender este lenguaje, en su mayor parte, no será más que definir nuevas funciones. Algunos usuarios han estado respaldando características de Rebol 3 en Rebol 2, por ejemplo.

Izkata
fuente
7

Ruby tiene una sintaxis bastante flexible, creo que es una forma de "extender el lenguaje dentro del lenguaje mismo".

Un ejemplo es el rastrillo . Está escrito en Ruby, es Ruby, pero parece hacer .

Para comprobar algunas posibilidades, puede buscar las palabras clave Ruby y metaprogramación .

Knut
fuente
13
La "sintaxis flexible" es MUY diferente de la "sintaxis extensible". Ha pasado mucho tiempo desde que programé en Ruby, pero Rake parece un uso bien diseñado de la sintaxis incorporada. En otras palabras, esto no es un ejemplo.
Thomas Eding
2
¿No es una cuestión de grado, no de tipo? ¿Cómo distinguiría entre un lenguaje de "sintaxis extensible" que puede extender algunos aspectos de su sintaxis pero no otros, y un lenguaje de "sintaxis flexible"?
Próxima tormenta el
1
Si la línea está borrosa, retrocedamos la línea para que se considere que C admite sintaxis extensible.
Thomas Eding
Para vincular con su ejemplo, trazaría la línea aquí: un lenguaje con sintaxis extensible puede hacer rake, que se parece a make. Se puede extender un lenguaje con sintaxis flexible (ja, buena combinación lingüística allí) para compilar y ejecutar archivos MAKE. Sin embargo, su punto de vista sobre el grado es bueno. Tal vez algunos lenguajes permitan compilar Make, pero no Python. Y otros permitirían ambos.
Clayton Stanley
Cualquier lenguaje completo debe ser capaz de procesar archivos Make. La flexibilidad de la sintaxis no es un factor más allá de lo difícil que sería.
Plataforma
7

Ampliar la sintaxis de la forma en que está hablando le permite crear idiomas específicos de dominio. Entonces, quizás la forma más útil de reformular su pregunta es, ¿qué otros idiomas tienen un buen soporte para idiomas específicos de dominio?

Ruby tiene una sintaxis muy flexible, y muchas DSL han florecido allí, como el rastrillo. Groovy incluye mucha de esa bondad. También incluye transformaciones AST, que son más directamente análogas a las macros Lisp.

R, el lenguaje para la computación estadística, permite que las funciones no evalúen sus argumentos. Utiliza esto para crear un DSL para especificar la fórmula de regresión. Por ejemplo:

y ~ a + b

significa "ajustar una línea de la forma k0 + k1 * a + k2 * b a los valores en y".

y ~ a * b

significa "ajustar una línea de la forma k0 + k1 * a + k2 * b + k3 * a * b a los valores en y".

Y así.

Martin C. Martin
fuente
2
Las transformaciones AST de Groovy son muy detalladas en comparación con las macros Lisp o Clojure. Por ejemplo, el ejemplo Groovy de más de 20 líneas en groovy.codehaus.org/Global+AST+Transformations podría reescribirse como una línea corta en Clojure, por ejemplo, `(esto (mensaje println ~)). No solo eso, sino que tampoco tendría que compilar el tarro, escribir los metadatos o cualquier otra cosa en esa página de Groovy.
Vorg van Geir
7

Converge es otro lenguaje de metaprogramación no lispy. Y, hasta cierto punto, C ++ también califica.

Podría decirse que MetaOCaml está bastante lejos de Lisp. Para un estilo totalmente diferente de extensibilidad de sintaxis, pero aún bastante potente, eche un vistazo a CamlP4 .

Nemerle es otro lenguaje extensible con una metaprogramación de estilo Lisp, aunque está más cerca de lenguajes como Scala.

Y, Scala pronto se convertirá en un lenguaje así también.

Editar: Olvidé el ejemplo más interesante: JetBrains MPS . No solo está muy distante de nada de Lispish, es incluso un sistema de programación no textual, con un editor que opera directamente en un nivel AST.

Edit2: para responder una pregunta actualizada: no hay nada único y excepcional en las macros de Lisp. En teoría, cualquier lenguaje puede proporcionar dicho mecanismo (incluso lo hice con C simple). Todo lo que necesita es un acceso a su AST y la capacidad de ejecutar código en tiempo de compilación. Alguna reflexión podría ayudar (consultar sobre los tipos, las definiciones existentes, etc.).

SK-logic
fuente
Su enlace Scala dice explícitamente que las macros propuestas "no pueden cambiar la sintaxis de Scala". (¡Interesante, enumera esto como una diferencia entre esa propuesta y las macros de preprocesador C / C ++!)
ruakh
@ruakh, sí, es el mismo enfoque que Converge y Template Haskell: la aplicación de macros está explícitamente marcada y no se puede mezclar con una sintaxis "normal". Pero, dentro puede tener cualquier sintaxis que desee, por lo que podría decirse que es una sintaxis extensible. El requisito de "no lisp", desafortunadamente, limita sus opciones a idiomas como este.
SK-logic
"Incluso lo hice con C simple": ¿Cómo es esto posible?
Giorgio
@Giorgio, por supuesto, modifiqué un compilador (agregué macros y una compilación de módulo incremental, que en realidad es bastante natural para C).
SK-logic
¿Por qué es necesario el acceso al AST?
Elliot Gorokhovsky
6

Prolog permite definir nuevos operadores que se traducen a términos compuestos del mismo nombre. Por ejemplo, esto define un has_catoperador y lo define como un predicado para verificar si una lista contiene el átomo cat:

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

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

El xfmedio que has_cates un operador postfix; el uso fxlo convertiría en un operador de prefijo y xfxlo convertiría en un operador de infijo, tomando dos argumentos. Consulte este enlace para obtener más detalles sobre cómo definir operadores en Prolog.

Ambroz Bizjak
fuente
5

TeX no se encuentra en la lista. Todos ustedes lo saben, ¿verdad? Se ve algo como esto:

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

... excepto que puede redefinir la sintaxis sin restricciones. A cada token (!) En el idioma se le puede asignar un nuevo significado. ConTeXt es un paquete de macros que ha reemplazado las llaves con llaves cuadradas:

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

El paquete de macros más común LaTeX también redefine el lenguaje para sus propósitos, por ejemplo, agregando la \begin{environment}…\end{environment}sintaxis.

Pero no se detiene ahí. Técnicamente, también podría redefinir los tokens para analizar lo siguiente:

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

Si, absolutamente posible. Algunos paquetes usan esto para definir pequeños lenguajes específicos de dominio. Por ejemplo, el paquete TikZ define una sintaxis concisa para dibujos técnicos, que permite lo siguiente:

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

Además, TeX es Turing completo, por lo que literalmente puede hacer todo con él. Nunca he visto esto utilizado en todo su potencial porque sería bastante inútil y muy complicado, pero es completamente posible hacer que el siguiente código sea analizable simplemente redefiniendo tokens (pero esto probablemente iría a los límites físicos del analizador, debido a que forma en que está construido):

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

Boo te permite personalizar mucho el idioma en tiempo de compilación a través de macros sintácticas.

Boo tiene una "tubería compilador extensible". Eso significa que el compilador puede llamar a su código para realizar transformaciones AST en cualquier momento durante la canalización del compilador. Como saben, cosas como Java's Generics o C # 's Linq son solo transformaciones de sintaxis en tiempo de compilación, por lo que esto es bastante poderoso.

En comparación con Lisp, la principal ventaja es que funciona con cualquier tipo de sintaxis. Boo está utilizando una sintaxis inspirada en Python, pero probablemente podría escribir un compilador extensible con una sintaxis C o Pascal. Y dado que la macro se evalúa en tiempo de compilación, no hay penalización de rendimiento.

Los inconvenientes, en comparación con Lisp, son:

  • Trabajar con un AST no es tan elegante como trabajar con expresiones s
  • Como la macro se invoca en tiempo de compilación, no tiene acceso a datos de tiempo de ejecución.

Por ejemplo, así es como podría implementar una nueva estructura de control:

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

uso:

repeatLines 2, "foo", "bar"

que luego se traduce, en tiempo de compilación, a algo como:

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

(Desafortunadamente, la documentación en línea de Boo siempre está desactualizada y ni siquiera cubre cosas avanzadas como esta. La mejor documentación para el idioma que conozco es este libro: http://www.manning.com/rahien/ )

nikie
fuente
1
La documentación web para esta característica está actualmente rota, y no escribo Boo yo mismo, pero pensé que sería una pena si se pasara por alto. Agradezco los comentarios de mod y volveré a considerar cómo hago para contribuir con información gratuita en mi tiempo libre.
Dan
4

La evaluación de Mathematica se basa en la coincidencia y reemplazo de patrones. Eso le permite crear sus propias estructuras de control, cambiar las estructuras de control existentes o cambiar la forma en que se evalúan las expresiones. Por ejemplo, podría implementar una "lógica difusa" como esta (un poco simplificado):

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]

Esto anula la evaluación de los operadores lógicos predefinidos &&, || ,! y la Ifcláusula incorporada .

Puede leer estas definiciones como definiciones de funciones, pero el significado real es: si una expresión coincide con el patrón descrito en el lado izquierdo, se reemplaza con la expresión en el lado derecho. Podría definir su propia cláusula If de esta manera:

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

SetAttributes[..., HoldRest] le dice al evaluador que debe evaluar el primer argumento antes de la coincidencia del patrón, pero mantener la evaluación para el resto hasta después de que el patrón haya sido emparejado y reemplazado.

Esto se usa ampliamente dentro de las bibliotecas estándar de Mathematica para, por ejemplo, definir una función Dque tome una expresión y evalúe su derivada simbólica.

nikie
fuente
3

Metalua es un lenguaje y un compilador compatible con Lua que proporciona esto.

  • Compatibilidad total con las fuentes y el código de bytes de Lua 5.1: semántica y sintaxis limpias y elegantes, increíble poder expresivo, buenas prestaciones, portabilidad casi universal. - Un sistema macro completo, similar en potencia a lo que ofrecen los dialectos de Lisp o Template Haskell; los programas manipulados pueden verse
    como código fuente, como árboles de sintaxis abstracta o como una mezcla arbitraria de los
    mismos, lo que mejor se adapte a su tarea.
  • Un analizador extensible dinámicamente, que le permite admitir sus macros con una sintaxis que combina muy bien con el resto del lenguaje.

  • Un conjunto de extensiones de lenguaje, todas implementadas como macros de metalua regulares.

Diferencias con Lisp:

  • No moleste a los desarrolladores con macros cuando no están escribiendo uno: la sintaxis y la semántica del lenguaje deberían ser las más adecuadas para el 95% de las veces cuando no estamos escribiendo macros.
  • Aliente a los desarrolladores a seguir las convenciones del lenguaje: no solo con las "mejores prácticas" que nadie escucha, sino ofreciendo una API que facilite la escritura de Metalua Way. La legibilidad por parte de otros desarrolladores es más importante y más difícil de lograr que la legibilidad de los compiladores, y para esto, tener un conjunto común de convenciones respetadas ayuda mucho.
  • Sin embargo, proporcione todo el poder que uno esté dispuesto a manejar. Ni Lua ni Metalua están obligados a la esclavitud y la disciplina, por lo que si sabes lo que estás haciendo, el idioma no se interpondrá en tu camino.
  • Haz que sea obvio cuando sucede algo interesante: todas las metaoperaciones ocurren entre + {...} y - {...}, y sobresalen visualmente del código normal.

Un ejemplo de aplicación es la implementación de la coincidencia de patrones tipo ML.

Ver también: http://lua-users.org/wiki/MetaLua

Clemente J.
fuente
Aunque Lua no es un Lisp, su lista de "diferencias" es bastante sospechosa (el único elemento relevante es el último). Y, por supuesto, la comunidad de Lisp no estaría de acuerdo con una queja de que uno no debería escribir / usar macros el 95% del tiempo: la forma de Lisp se inclina hacia algo como el 95% del tiempo usando y escribiendo DSL, además de macros, de curso.
SK-logic
2

Si está buscando idiomas que sean extensibles, debería echar un vistazo a Smalltalk.

En Smalltalk, la única forma de programar es extender el lenguaje. No hay diferencia entre el IDE, las bibliotecas o el lenguaje en sí. Todos están tan entrelazados que Smalltalk a menudo se conoce como un entorno en lugar de un lenguaje.

No escribe aplicaciones independientes en Smalltalk, sino que extiende el entorno del lenguaje.

Visite http://www.world.st/ para ver un puñado de recursos e información.

Me gustaría recomendar Pharo como dialecto de entrada al mundo de Smalltalk: http://pharo-project.org

Espero que haya ayudado!

Bernat Romagosa
fuente
1
Suena interesante.
Thomas Eding
1

Existen herramientas que permiten crear idiomas personalizados sin escribir un compilador completo desde cero. Por ejemplo, está Spoofax , que es una herramienta de transformación de código: coloca reglas gramaticales y de transformación de entrada (escritas de manera declarativa de muy alto nivel), y luego puede generar código fuente Java (u otro lenguaje, si le importa lo suficiente) de un lenguaje personalizado diseñado por ti.

Por lo tanto, sería posible tomar la gramática del lenguaje X, definir la gramática del lenguaje X '(X con sus extensiones personalizadas) y la transformación X' → X, y Spoofax generará un compilador X '→ X.

Actualmente, si entiendo correctamente, el mejor soporte es para Java, con el desarrollo de C # en desarrollo (o eso escuché). Sin embargo, esta técnica podría aplicarse a cualquier lenguaje con gramática estática (por ejemplo, probablemente no Perl ).

liori
fuente
1

Forth es otro idioma que es altamente extensible. Muchas implementaciones de Forth consisten en un pequeño núcleo escrito en ensamblador o C, luego el resto del lenguaje está escrito en el mismo Forth.

También hay varios lenguajes basados ​​en pila que están inspirados en Forth y comparten esta característica, como Factor .

Dave Kirby
fuente
0

Funge-98

La función de huella digital de Funge-98 permite hacer una reestructuración completa de toda la sintaxis y la semántica del lenguaje. Pero solo si el implementador proporciona un mecanismo de huellas dactilares que permitió al usuario alterar programáticamente el idioma (esto es teóricamente posible implementar dentro de la sintaxis y semántica Funge-98 normales). Si es así, uno podría literalmente hacer que el resto del archivo (o cualquier parte del archivo) actúe como C ++ o Lisp (o lo que quiera).

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

Thomas Eding
fuente
¿Por qué publicaste esto por separado en lugar de agregarlo a tu respuesta anterior ?
mosquito
1
Porque Funge no tiene nada que ver con Haskell.
Thomas Eding
-1

Para obtener lo que estás buscando, realmente necesitas esos paréntesis y una falta de sintaxis. Algunos lenguajes basados ​​en sintaxis pueden acercarse, pero no es lo mismo que una macro real.

mike30
fuente