* это перевод статьи с 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