Парадигма | Мультипарадигма : параллельная , функциональная |
---|---|
Семья | Эрланг , Лисп |
Разработано | Роберт Вирдинг |
Разработчик | Роберт Вирдинг |
Впервые появился | 2008 ( 2008 ) |
Стабильный релиз | 2.1.1 / 6 января 2023 г. ( 2023-01-06 ) |
Дисциплина набора текста | динамичный , сильный |
Язык реализации | Эрланг |
ОС | Кроссплатформенный |
Лицензия | Апач 2.0 |
Расширения имени файла | .lfe .hrl |
Веб-сайт | lfe.io |
Под влиянием | |
Erlang , Common Lisp , Maclisp , Scheme , Elixir , Clojure , Hy | |
Под влиянием | |
Джокса, Конкурентный комбинатор |
Lisp Flavored Erlang ( LFE ) — это функциональный , параллельный , собирающий мусор , универсальный язык программирования и диалект Lisp , созданный на основе Core Erlang и виртуальной машины Erlang ( BEAM ). LFE создан на основе Erlang, чтобы предоставить синтаксис Lisp для написания распределенных, отказоустойчивых , мягких приложений реального времени , работающих без остановок. LFE также расширяет Erlang для поддержки метапрограммирования с макросами Lisp и улучшенного опыта разработки с многофункциональным циклом чтения-вычисления-печати (REPL). [1] LFE активно поддерживается во всех последних выпусках Erlang; самая старая поддерживаемая версия Erlang — R14.
Первоначальная работа над LFE началась в 2007 году, когда Роберт Вирдинг начал создавать прототип Lisp, работающий на Erlang. [2] Эта работа была сосредоточена в первую очередь на разборе и исследовании того, как может выглядеть реализация. В то время не использовалась система контроля версий, поэтому отслеживание точных начальных дат было несколько проблематичным. [2]
Вирдинг объявил о первом выпуске LFE в почтовом списке Erlang Questions в марте 2008 года. [3] Этот выпуск LFE был очень ограничен: он не обрабатывал рекурсивные letrec
s, binary
s, receive
, или try
; он также не поддерживал оболочку Lisp. [4]
Первоначальная разработка LFE была выполнена с использованием версии R12B-0 Erlang [5] на ноутбуке Dell XPS. [4]
1958 | 1960 | 1965 | 1970 | 1975 | 1980 | 1985 | 1990 | 1995 | 2000 | 2005 | 2010 | 2015 | 2020 | ||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
LISP 1, 1.5, LISP 2 (заброшен) | |||||||||||||||
Маклисп | |||||||||||||||
Интерлисп | |||||||||||||||
молдавский лей | |||||||||||||||
Лисп-машина Лисп | |||||||||||||||
Схема | Р5РС | Р6РС | R7RS маленький | ||||||||||||
НОЛЬ | |||||||||||||||
ZIL (язык реализации Zork) | |||||||||||||||
Франц Лисп | |||||||||||||||
Общий Лисп | стандарт ANSI | ||||||||||||||
Ле Лисп | |||||||||||||||
Схема Массачусетского технологического института | |||||||||||||||
XLISP | |||||||||||||||
Т | |||||||||||||||
Chez Схема | |||||||||||||||
Emacs Лисп | |||||||||||||||
АвтоЛИСП | |||||||||||||||
ПикоЛисп | |||||||||||||||
Гамбит | |||||||||||||||
EuLisp | |||||||||||||||
ИСЛИСП | |||||||||||||||
OpenLisp | |||||||||||||||
Схема ПЛТ | Ракетка | ||||||||||||||
новыйLISP | |||||||||||||||
GNU-хитрость | |||||||||||||||
Визуальный ЛИСП | |||||||||||||||
Кложур | |||||||||||||||
Дуга | |||||||||||||||
ЛФЭ | |||||||||||||||
Хай | |||||||||||||||
Хиалисп |
Роберт Вирдинг заявил, что было несколько причин, по которым он начал разрабатывать язык программирования LFE: [2]
lfe
с использованием обоих языков иlfescript
Как и Lisp, LFE — это язык, ориентированный на выражения . В отличие от не- гомиконических языков программирования, Lisp не делает или делает небольшое синтаксическое различие между выражениями и операторами : весь код и данные записываются как выражения. LFE привнес гомоиконичность в Erlang VM.
В LFE тип данных list записывается с элементами, разделенными пробелами и заключенными в скобки. Например, это список, элементами которого являются целые числа и , а также атом [[foo| ]]. Эти значения неявно типизированы: они представляют собой соответственно два целых числа и специфичный для Lisp тип данных, называемый символическим атомом , и не должны быть объявлены как таковые.(list 1 2 'foo)
1
2
foo
Как видно из примера выше, выражения LFE записываются в виде списков с использованием префиксной нотации . Первый элемент в списке — это имя формы , т. е. функции, оператора или макроса. Остальная часть списка — это аргументы.
Операторы LFE-Erlang используются таким же образом. Выражение
( * ( + 1 2 3 4 5 6 ) 2 )
вычисляется как 42. В отличие от функций в Erlang и LFE, арифметические операторы в Lisp являются вариативными (или n-арными ), способными принимать любое количество аргументов.
LFE имеет lambda , как и Common Lisp. Однако, он также имеет lambda-match для учета возможностей Erlang по сопоставлению с образцом в анонимных вызовах функций.
Этот раздел не представляет собой полное сравнение Erlang и LFE, но может дать представление.
Эрланг:
1 > { Лен , Статус , Сообщение } = { 8 , ок , «Триллиан» }. { 8 , ок , «Триллиан» } 2 > Сообщение . "Триллиан"
ЛФЭ:
lfe> ( set ( tuple len status msg ) #( 8 ok "Trillian" )) lfe> ;; или с синтаксисом кортежа литерала LFE: lfe> ( set `#(, len , status , msg ) #( 8 ok "Trillian" )) #( 8 ok "Trillian" ) lfe> msg "Trillian"
Эрланг:
1 > [ trunc ( математика : pow ( 3 , X )) || X <- [ 0 , 1 , 2 , 3 ]]. [ 1 , 3 , 9 , 27 ]
ЛФЭ:
lfe> ( list-comp (( <- x ' ( 0 1 2 3 ))) ( trunc ( math:pow 3 x ))) ( 1 3 9 27 )
Или идиоматический функциональный стиль:
lfe> ( списки: карта ( лямбда ( x ) ( усечение ( математика: сила 3 x ))) ' ( 0 1 2 3 )) ( 1 3 9 27 )
Эрланг:
right_number ( X ) когда X == 42 ; X == 276709 -> true ; right_number (_) -> false .
ЛФЭ:
( defun right-number? (( x ) ( when ( orelse ( == x 42 ) ( == x 276709 ))) 'true ) (( _ ) 'false ))
Эрланг:
сумма ( L ) -> сумма ( L , 0 ). сумма ([], Всего ) - > Всего ; сумма ([ H | T ], Всего ) -> сумма ( T , H + Всего ).
ЛФЭ:
( defun sum ( l ) ( sum l 0 )) ( defun sum (( ' () итого ) итого ) ((( cons h t ) итого ) ( сумма t ( + h итого ))))
или используя литерал ``cons`` вместо формы конструктора:
( defun sum ( l ) ( sum l 0 )) ( defun sum (( ' () итог ) итог ) (( ` ( , час . , t ) итог ) ( сумма t ( + час итог ))))
Эрланг:
handle_info ( ping , #state { remote_pid = undefined } = State ) -> gen_server : cast ( self (), ping ), { noreply , State }; handle_info ( ping , State ) -> { noreply , State };
ЛФЭ:
( defun handle_info (( 'ping ( = ( match-state remote-pid ' undefined ) state )) ( gen_server:cast ( self ) 'ping ) `#( noreply , state )) (( 'ping state ) `#( noreply , state )))
Эрланг:
universal_server () -> receive { become , Func } -> Func () end .
ЛФЭ:
( defun universal-server () ( receive (( tuple 'become func ) ( funcall func ))))
или:
( defun universal-server () ( receive ( `#( become , func ) ( funcall func ))))
Вызовы функций Erlang имеют вид (<модуль>:<функция> <arg1> ... <argn>) :
( io:format "Привет, мир!" )
Использование рекурсии для определения функции Аккермана :
( defun акерман (( 0 n ) ( + n 1 )) (( m 0 ) ( акерман ( - m 1 ) 1 )) (( m n ) ( акерман ( - m 1 ) ( акерман m ( - n 1 )))))
Функции сочинения:
( defun compose ( f g ) ( лямбда ( x ) ( funcall f ( funcall g x )))) ( defun check () ( let* (( sin-asin ( compose #' sin/1 #' asin/1 )) ( expected ( sin ( asin 0.5 ))) ( compose-result ( funcall sin-asin 0.5 ))) ( io:format "Ожидаемый ответ: ~p~n" ( list expected )) ( io:format "Ответ с помощью compose: ~p~n" ( list compose-result ))))
Передача сообщений с помощью легковесных «процессов» Erlang:
( defmodule messenger-back ( export ( print-result 0 ) ( send-message 2 ))) ( defun print-result () ( receive (( tuple pid msg ) ( io:format "Получено сообщение: '~s'~n" ( list msg )) ( io:format "Отправка сообщения процессу ~p ...~n" ( list pid )) ( ! pid ( tuple msg )) ( print-result )))) ( defun send-message ( calls-pid msg ) ( let (( spawned-pid ( spawn 'messenger-back ' print-result ()))) ( ! spawned- pid ( tuple calls-pid msg ))))
Несколько одновременных HTTP-запросов:
( defun parse-args ( flag ) "Для заданного одного или нескольких аргументов командной строки извлечь переданные значения. Например, если через командную строку было передано следующее: $ erl -мой-флаг мое-значение-1 -мой-флаг мое-значение-2 Затем его можно извлечь в программе LFE, вызвав эту функцию: (let ((args (parse-args 'my-flag))) ... ) В этом примере значение, присвоенное переменной arg, будет списком, содержащим значения my-value-1 и my-value-2." ( let (( `#( ok , data ) ( init:get_argument flag ))) ( lists:merge data ))) ( defun get-pages () "Без аргументов предположим, что параметр 'url был передан через командную строку." ( let (( urls ( parse-args 'url ))) ( get-pages urls ))) ( defun get-pages ( urls ) "Запустить inets и сделать (потенциально много) HTTP-запросов." ( inets:start ) ( plists:map ( lambda ( x ) ( get-page x )) urls )) ( defun get-page ( url ) "Сделать один HTTP-запрос." ( let* (( method 'get ) ( headers ' ()) ( request-data `#(, url , headers )) ( http-options ()) ( request-options ' ( #( sync false )))) ( httpc:request method request-data http-options request-options ) ( receive ( `#( http #(, request-id #( error , reason ))) ( io:format "Ошибка: ~p~n" ` ( , reason ))) ( `#( http #(, request-id , result )) ( io:format "Результат: ~p~n" ` ( , result ))))))