LispyScript — JavaScript в стиле Lisp

в 19:23, , рубрики: javascript, метки: ,

* это перевод статьи с DailyJS

Введение

LispyScript — древовидный язык программирования, который компилится в JavaScript. Собственно говоря, это что-то между JavaScript и Lisp.
Скрипт на Lispy состоит из подобных выражений:

(<function> arg1 arg2 arg3 ...)


Данное выражение вызывает функцию (вообще это не совсем так, но это позже).
Первый элемент указывает на функцию. Остальные — аргументы.

(console.log "abc")

Да, совсем забыл: поиграться можно тут.

Можно вызвать вот так:

 (console.log "2 + 2 = %d" (+ 2 2)) 

В JS это так:

 console.log("2 + 2 = %d", (2 + 2));

Ну а теперь всем нам знакомая структура HTML:

<html lang="en">
  <head>
    <title>My Home Page</title>
  </head>
  <body>
    <h1>Welcome to LispyScript</h1>
  </body>
</html>

А теперь шаблоны Lispy:

(html {lang: "en"}
  (head
    (title "My Home Page"))
  (body
    (h1 "Welcome to LispyScript")))

Про шаблоны позже, сейчас важно увидеть древовидную структуру.

Макросы

Одна из важнейших частей Lispy. Макросы никак не компилятся в JS, но они расширяют компилятор. Давайте напишем макрос print:

(macro print (str rest...)
  (console.log ~str ~rest...))

(print "Hello print macro!")
(print "2 + 2 = %d" (+ 2 2))

console.log("Hello print macro!")
console.log("2 + 2 = %d", (2 + 2));

Приведённый выше макрос расширяет Lispy. Выражение macro принимает первым параметром имя макроса, дальше в скобках параметры, а затем код, в который компилируется вызов макроса.
Оператор ~ разыменует параметры. Переменная rest… содержит все переданные параметры, идущие после str.

Компилятор работает в 2 этапа: вначале макрос преобразует код. Т.е. из

 (print "Hello print macro!")

Он создаёт:

 (console.log "Hello print macro!") 

Ну а дальше уже компилит в JS. Аналогично:

 (print "2 + 2 = %d" (+ 2 2)) ; lispy

(console.log "2 + 2 = %d" (+ 2 2)) ; lispy

 console.log("2 + 2 = %d", (2 + 2)); // js

Можно спросить, а почему не использовать вместо макроса функцию? Давайте попробуем:

(var print
  (function (data value)
    (console.log data value)))

А теперь сравните получившийся код:

// макрос
console.log("2 + 2 = %d", (2 + 2));

// функция
var print = function(data,value) {
    return console.log(data,value);
};
print("2 + 2 = %d",(2 + 2));
Макросы могут быть опасны

Не надо ждать от макроса, что он будет вести себя как функция. Очень часто лучше использовать функцию вместо макроса.
Пример: напишем макрос для вычисления квадрата числа:

(macro square (x)
  (* ~x ~x))

(console.log (square 2))

И этот код будет прекрасно работать, выведет 4. В JS это так:

console.log((2 * 2));

А теперь пробуем:

(var i 2)
(console.log (square i++))

И у нас возвращается число 6 вместо 9. Всё сразу становится понятно, если взглянуть на скомпиленный код:

var i = 2;
console.log((i++ * i++));

В случае функции значение вычисляется заранее, а вот в случае макроса — нет. Так что это нужно запомнить и понять.

Заключение

В общем, Lispy прелагает альтернативный путь написания скриптов. Макросы являются очень мощным средством, но их лучше использовать с осторожностью.

P. S.

Также есть Javathcript. Правда он без макросов.

Автор: Keyten

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js