* это перевод статьи с DailyJS
LispyScript — древовидный язык программирования, который компилируется в JavaScript. Собственно говоря, это что-то между JavaScript и Lisp.
Скрипт на Lispy состоит из подобных выражений:
Данное выражение вызывает функцию (вообще говоря, это не совсем так, но об этом позже).
Первый элемент указывает на функцию. Остальные — на аргументы.
Да, чуть не забыл: поиграться можно тут.
Например, функцию можно вызвать вот так:
Ну а в JS это выглядит так:
Всем нам знакомая структура HTML:
В шаблонах Lispy это выглядит немного иначе:
Но про шаблоны позже, сейчас важно увидеть древовидную структуру.
Одна из важнейших частей Lispy. Макросы никак не компилируются в JS, но они могут расширять компилятор. Давайте, например, напишем макрос print:
Приведённый выше макрос расширяет Lispy. Выражение macro принимает первым параметром имя макроса, дальше в скобках параметры, а затем код, в который компилируется вызов макроса.
Оператор ~ разыменует параметры. Переменная rest… содержит все переданные параметры, идущие после str.
Компилятор работает в 2 этапа: вначале макросы преобразуются в код. Т.е. из
Он создаёт:
Ну а дальше уже компилирует в JS. Аналогично:
Можно спросить, а почему не использовать вместо макроса функцию? Давайте попробуем:
А теперь сравните получившийся код:
Не стоит ждать от макроса, что он будет вести себя как функция. Часто лучше использовать функцию, а не макрос.
Пример: напишем макрос для вычисления квадрата числа:
И этот код будет прекрасно работать, выведет 4. В JS это так:
А теперь пробуем:
И у нас возвращается число 6 вместо 9. Почему так, становится понятно, если взглянуть на скомпилированный код:
В случае функции значение вычисляется заранее, а вот в случае макроса — нет. Это нужно понять и запомнить.
В целом, Lispy прелагает альтернативный путь написания скриптов. Макросы являются очень мощным средством, но их лучше использовать с осторожностью.
Также есть Javathcript. Правда он без макросов.
UPD. Ещё ClojureScript, спасибо за подсказку monolithed
Введение
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