Как стать автором
Обновить

LispyScript — JavaScript в стиле Lisp

Время на прочтение2 мин
Количество просмотров8.7K
* это перевод статьи с 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. Правда он без макросов.
UPD. Ещё ClojureScript, спасибо за подсказку monolithed
Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
Всего голосов 28: ↑26 и ↓2+24
Комментарии16

Публикации

Истории

Работа

Ближайшие события