Lisp Flavored Erlang ( LFE ) es un lenguaje de programación funcional , concurrente , recolectado de basura , de propósito general y dialecto Lisp construido en Core Erlang y la máquina virtual Erlang ( BEAM ). LFE se basa en Erlang para proporcionar una sintaxis Lisp para escribir aplicaciones distribuidas, tolerantes a fallas , suaves en tiempo real e ininterrumpidas. LFE también amplía Erlang para admitir la metaprogramación con macros Lisp y una experiencia de desarrollador mejorada con un bucle de lectura-evaluación-impresión (REPL) rico en funciones . [1] LFE cuenta con el apoyo activo de todas las versiones recientes de Erlang; la versión más antigua de Erlang compatible es R14.
Paradigma | Multi-paradigma : concurrente , funcional |
---|---|
Familia | Erlang , Lisp |
Diseñada por | Robert Virding |
Desarrollador | Robert Virding |
Apareció por primera vez | 2008 |
Lanzamiento estable | 1.3 / 4 de junio de 2017 |
Disciplina de mecanografía | dinámico , fuerte |
Lenguaje de implementación | Erlang |
Plataforma | IA-32 , x86-64 |
SO | Multiplataforma |
Licencia | Apache 2.0 |
Extensiones de nombre de archivo | .lfe .hrl |
Sitio web | lfe |
Influenciado por | |
Erlang , Common Lisp , Maclisp , Scheme , Elixir , Clojure , Hy | |
Influenciado | |
Joxa, maquinista concurrente |
Historia
Versión inicial
El trabajo inicial en LFE comenzó en 2007, cuando Robert Virding comenzó a crear un prototipo de Lisp ejecutándose en Erlang. [2] Este trabajo se centró principalmente en analizar y explorar cómo se vería una implementación. En ese momento no se utilizaba ningún sistema de control de versiones, por lo que el seguimiento de las fechas iniciales exactas es algo problemático. [2]
Virding anunció el primer lanzamiento de LFE en la lista de correo de Preguntas de Erlang en marzo de 2008. [3] Este lanzamiento de LFE era muy limitado: no manejaba letrec
s, binary
s receive
, o recursivos try
; tampoco soportaba un shell Lisp. [4]
El desarrollo inicial de LFE se realizó con la versión R12B-0 de Erlang [5] en una computadora portátil Dell XPS. [4]
Motivos
Robert Virding ha declarado que hubo varias razones por las que comenzó el lenguaje de programación LFE: [2]
- Tenía experiencia previa en programación en Lisp.
- Dada su experiencia previa, estaba interesado en implementar su propio Lisp.
- En particular, quería implementar un Lisp en Erlang: no solo tenía curiosidad por ver cómo funcionaría y se integraría con Erlang, quería ver cómo se vería .
- Desde que ayudó a crear el lenguaje de programación Erlang, había tenido el objetivo de hacer un Lisp diseñado específicamente para ejecutarse en el BEAM y capaz de interactuar completamente con Erlang / OTP.
- Quería experimentar compilando otro idioma en Erlang. Como tal, vio LFE como un medio para explorar esto generando Core Erlang y conectándolo al backend del compilador de Erlang.
Características
- Un idioma dirigido a la máquina virtual Erlang (BEAM)
- Integración perfecta de Erlang : llamadas a funciones de Erlang sin penalización (y viceversa)
- Metaprogramación a través de macros Lisp y la homoiconicidad de un Lisp
- Documentación de estilo Lisp común a través de comentarios de código fuente y cadenas de documentación
- Programación concurrente de arquitectura de nada compartido a través del paso de mensajes ( modelo Actor )
- Énfasis en la recursividad y las funciones de orden superior en lugar del bucle basado en efectos secundarios
- Un ciclo completo de lectura-evaluación-impresión (REPL) para desarrollo y pruebas interactivos (a diferencia del shell de Erlang, LFE REPL admite definiciones de funciones y macros)
- La coincidencia de patrones
- Carga de código en caliente
- Una separación Lisp-2 de espacios de nombres para variables y funciones
- Interacción de Java a través de JInterface y Erjang
- Habilidades de scripting con ambos
lfe
ylfescript
Sintaxis y semántica
Expresiones simbólicas (expresiones S)
Como Lisp, LFE es un lenguaje orientado a expresiones . A diferencia de los lenguajes de programación no homoicónicos , Lisps hace poca o ninguna distinción sintáctica entre expresiones y declaraciones : todo el código y los datos se escriben como expresiones. LFE trajo homoiconicidad a Erlang VM.
Liza
En LFE, el tipo de datos de lista se escribe con sus elementos separados por espacios en blanco y entre paréntesis. Por ejemplo, es una lista cuyos elementos son los enteros y , y el átomo . Estos valores se escriben implícitamente: son respectivamente dos enteros y un tipo de datos específico de Lisp llamado átomo simbólico , y no es necesario declararlos como tales.(list 1 2 'foo)
1
2
foo
Como se ve en el ejemplo anterior, las expresiones LFE se escriben como listas, usando notación de prefijo . El primer elemento de la lista es el nombre de un formulario , es decir, una función, operador o macro. El resto de la lista son los argumentos.
Operadores
Los operadores LFE-Erlang se utilizan de la misma forma. La expresion
( * ( + 1 2 3 4 5 6 ) 2 )
se evalúa como 42. A diferencia de las funciones en Erlang y LFE, los operadores aritméticos en Lisp son variadic (o n-ary ), capaces de tomar cualquier número de argumentos.
Expresiones lambda y definición de funciones
LFE tiene lambda , al igual que Common Lisp. Sin embargo, también tiene lambda-match para tener en cuenta las capacidades de coincidencia de patrones de Erlang en llamadas a funciones anónimas.
Modismos de Erlang en LFE
Esta sección no representa una comparación completa entre Erlang y LFE, pero debería dar una idea.
La coincidencia de patrones
Erlang:
1 > { Len , Status , Msg } = { 8 , ok , "Trillian" }. { 8 , ok , "Trillian" } 2 > Msj . "Trillian"
LFE:
> ( set ( tuple len status msg ) # ( 8 ok "Trillian" )) # ( 8 ok "Trillian" ) > msg "Trillian"
Lista de comprensiones
Erlang:
1 > [ trunc ( matemáticas : pow ( 3 , X )) || X <- [ 0 , 1 , 2 , 3 ]]. [ 1 , 3 , 9 , 27 ]
LFE:
> ( list-comp (( <- x ' ( 0 1 2 3 ))) ( trunc ( matemáticas: pow 3 x ))) ( 1 3 9 27 )
O estilo funcional idiomático:
> ( listas: mapa ( lambda ( x ) ( trunc ( matemáticas: pow 3 x ))) ' ( 0 1 2 3 )) ( 1 3 9 27 )
Guardias
Erlang:
número_derecha ( X ) cuando X == 42 ; X == 276709 -> cierto ; número_derecha (_) -> falso .
LFE:
( defun número derecho? (( x ) ( cuando ( orelse ( == x 42 ) ( == x 276709 ))) 'verdadero ) (( _ ) ' falso ))
Cons'ing en los jefes de función
Erlang:
suma ( L ) -> suma ( L , 0 ). suma ([], Total ) -> Total ; suma ([ H | T ], Total ) -> suma ( T , H + Total ).
LFE:
( suma defun ( l ) ( suma l 0 )) ( suma defun (( ' () total ) total ) ((( cons h t ) total ) ( suma t ( + h total ))))
o usando un literal `` cons '' en lugar de la forma del constructor:
( suma defun ( l ) ( suma l 0 )) ( suma defun (( ' () total ) total ) (( ` ( , h . , t ) total ) ( suma t ( + h total ))))
Coincidencia de registros en los cabezales de función
Erlang:
handle_info ( ping , #state { remote_pid = undefined } = State ) -> gen_server : cast ( self (), ping ), { noreply , State }; handle_info ( ping , estado ) -> { norespuesta , estado };
LFE:
( defun handle_info (( 'ping ( = ( match-state remote-pid ' undefined ) state )) ( gen_server: cast ( self ) 'ping ) `# ( noreply , state )) (( ' ping state ) ` # ( noreply , estado )))
Recibir mensajes
Erlang:
universal_server () -> recibir { convertirse , Func } -> Func () final .
LFE:
( defun universal-server () ( recibir (( tupla 'se convierte en func ) ( funcall func ))))
o:
( defun universal-server () ( recibir ( `# ( convertirse , func ) ( funcall func ))))
Ejemplos de
Interoperabilidad de Erlang
Las llamadas a las funciones de Erlang tienen la forma (
( io: formato "¡Hola, mundo!" )
Paradigma funcional
Usando la recursividad para definir la función de Ackermann :
( defun ackermann (( 0 n ) ( + n 1 )) (( m 0 ) ( ackermann ( - m 1 ) 1 )) (( m n ) ( ackermann ( - m 1 ) ( ackermann m ( - n 1 )) )))
Funciones de composición:
( defun compose ( f g ) ( lambda ( x ) ( funcall f ( funcall g x ))))( defun check () ( let * (( sin-asin ( compose # ' sin / 1 #' asin / 1 )) ( esperado ( sin ( asin 0.5 ))) ( compose-result ( funcall sin-asin 0.5 ))) ( io: formato "Respuesta esperada: ~ p ~ n" ( lista esperada )) ( io: formato "Respuesta con redactar: ~ p ~ n" ( lista compose-resultado ))))
Concurrencia
Paso de mensajes con los "procesos" ligeros de Erlang:
( defmodule messenger-back ( exportar ( imprimir resultado 0 ) ( enviar mensaje 2 )))( defun print-result () ( receive (( tuple pid msg ) ( io: format "Received message: '~ s' ~ n" ( list msg )) ( io: format "Enviando mensaje al proceso ~ p ... ~ n " ( lista pid )) ( ! pid ( tupla msg )) ( resultado de impresión ))))( defun enviar-mensaje ( llamando-pid msg ) ( let (( spawned-pid ( spawn 'messenger-back ' print-result ()))) ( ! spawned-pid ( tupla llamando-pid msg ))))
Varias solicitudes HTTP simultáneas:
( defun parse-args ( bandera ) "Dados uno o más argumentos de la línea de comandos, extrae los valores pasados. Por ejemplo, si se pasó lo siguiente a través de la línea de comando: $ erl -mi-bandera mi-valor-1 -mi-bandera mi-valor-2 Luego, se podría extraer en un programa LFE llamando a esta función: (let ((args (parse-args 'my-flag))) ... ) En este ejemplo, el valor asignado a la variable arg sería una lista que contiene los valores my-value-1 y my-value-2. " ( let (( ` # ( ok , data ) ( init: get_argument flag ))) ( listas: fusionar datos )))( defun get-pages () "Sin argumento, suponga que 'el parámetro url se pasó a través de la línea de comando." ( let (( urls ( parse-args ' url ))) ( get-pages urls )))( defun get-pages ( urls ) "Iniciar inets y realizar (potencialmente muchas) solicitudes HTTP." ( inets: start ) ( plists: map ( lambda ( x ) ( get-page x )) urls ))( defun get-page ( url ) "Realizar una sola solicitud HTTP." ( let * (( método 'get ) ( headers ' ()) ( request-data `# (, url , headers )) ( http-options () ) ( opciones de solicitud ' ( # ( sincronización falsa )))) ( httpc: método de solicitud datos de solicitud opciones http opciones de solicitud ) ( recibir ( `# ( http # (, id de solicitud # ( error , motivo )) ) ( io: formato "Error: ~ p ~ n" ` ( , motivo ))) ( ` # ( http # (, id-solicitud , resultado )) ( io: formato "Resultado: ~ p ~ n" ` ( , resultado ))))))
Referencias
- ^ Virding, Robert. "Lisp Flavored Erlang" (PDF) . Fábrica de Erlang . Consultado el 17 de enero de 2014 .
- ^ a b c "Historia de LFE en la lista de correo Lisp Flavored Erlang" . Consultado el 28 de mayo de 2014 .
- ^ "Anuncio de LFE en la lista de correo de preguntas de Erlang" . Consultado el 17 de enero de 2014 .
- ^ a b Armstrong, Joe; Virding, Robert (30 de diciembre de 2013). "Hardware utilizado en el desarrollo de Erlang y LFE" (intercambio de correo electrónico). Entrevistado por Duncan McGreggor . Consultado el 17 de enero de 2014 .
- ^ "Seguimiento del anuncio de LFE en la lista de correo de preguntas de Erlang" . Consultado el 17 de enero de 2014 .
enlaces externos
- Página web oficial
- LFE en GitHub
- Inicio rápido de LFE
- Guía del usuario de LFE
- LFE en código Rosetta