Природа Лиспа
Сибу2015-01-27 00:38:48 Природа ЛиспаСлава Ахмечет
Переводчик Алек Джанг
Источник:woohoo.def macro.org/ramblings/com…
Введение
Когда я впервые наткнулся на кого-то, восхваляющего Lisp в некоторых уголках сети, К тому времени я уже был опытным программистом.
В моем резюме диапазон языков, которыми я овладел, довольно широк, например, C++, Java, основные языки C# и т. д.
Я чувствую, что знаю почти все о языках программирования. Когда дело доходит до языков программирования, мне кажется, что я не
Какая тоже большая проблема. На самом деле я очень ошибался.
Я попробовал немного изучить Лисп и сразу же уперся в стену. Я был в шоке от примера кода. Я думаю, что много первых встреч
Люди, использующие язык Lisp, должны были испытывать схожие чувства. Синтаксис Лиспа слишком низок. Изобретатель языка не
Желая придумать набор красивой грамматики, Кто хотел бы этому научиться. Во всяком случае, я был действительно захвачен этими уродливыми бесчисленными
Скобки сбивают с толку.
Когда я пришел в себя, я поговорил с бандой в сообществе Lisp о своем разочаровании. В результате сразу возник большой набор
Теория разбита, и эту теорию можно увидеть повсюду в сообществе Лиспа, и это почти условность. Например: круглые скобки в Лиспе просто поверхностны.
Например, у Lisp нет разницы в способе выражения кода и данных, и он намного умнее, чем синтаксис XML, поэтому у него есть бесконечные преимущества.
где; Лисп обладает мощными метаязыковыми возможностями, программисты могут писать самоподдерживающийся код; Лисп может создавать иголки.
языковые подмножества для конкретных приложений; Нет четкой границы между временем выполнения Lisp и временем компиляции и т.д., и т.д., и т.п. Этот
Такой длинный комплимент хоть и выглядит довольно трогательно, но для меня ничего не значит. Никто не может показать мне, как эти вещи работают
приложение, потому что эти вещи обычно используются только в больших системах. Я утверждаю, что эти вещи традиционным языком
То же самое можно сделать. После долгих споров с другими я, наконец, отказался от изучения Лиспа. почему бы
Как насчет того, чтобы потратить месяцы на изучение языка с такой уродливой грамматикой?Концепции этого языка настолько неясны, что нечего понимать
пример. Может быть, этот язык не для таких, как я, для изучения.
В течение нескольких месяцев, Я под тяжестью этих апологетов Лиспа. Я запутался в один момент. я знаю, некоторые
Самые умные люди, я их очень уважаю, и я вижу, как их похвала Лиспу достигает религиозных высот. Это
Дескать, в Лиспе должно быть что-то таинственное, я терпеть не могу собственного невежества в этом, любопытство и жажда знаний - самое главное.
Неостанавливаемый. Так что я стиснул зубы и погрузился в изучение Лиспа.После нескольких месяцев тяжелой и кропотливой практики я, наконец,
Я видел источник этой бесконечной весны. Переродившись, пройдя муки семи адов
Потом, наконец, я понял.
Озарение пришло внезапно. много раз, Я слышал, как другие цитируют Рэймонда.
По словам автора эпизода >>, известного теоретика хакерского сообщества): «Язык Лисп достоин изучения. Когда вы изучаете Лисп, вы
будет иметь глубокий опыт. Даже если вы обычно не программируете на Лиспе, это сделает вас лучшим программистом».
Раньше я понятия не имел, что означают эти слова, и не верил, что они верны. Но теперь я понимаю. Эти слова содержат
Правда далеко за пределами того, что я себе представлял в прошлом. Я почувствовал божественное чувство внутри себя, мгновенное прозрение, которое почти заставило меня
Принципиально изменились представления о информатике.
момент просветления, Я стал поклонником Лиспа. Я испытал то, что чувствует религиозный гуру: должен передать свои знания
Рассредоточьтесь, по крайней мере, 10 заблудших душ должны быть спасены. В обычном порядке я эти истины (т.е. только начал
Трюк, над которым в начале разобрались другие, но теперь я понимаю настоящий смысл) и рассказываю другим. Результат был настолько разочаровывающим,
Лишь несколько человек проявили небольшой интерес к моему настоянию, но после нескольких взглядов на код Лиспа они ушли.
сделал. Таким образом, на создание нескольких вентиляторов Lisp могут уйти годы, но я думаю, что результаты будут слишком плохими.
Все в порядке, я должен думать о лучшем способе.
Я глубоко задумался над этим вопросом. Есть ли что-то очень сложное в Лиспе, Так много опытных программистов
Не можете понять? Нет, нет ничего абсолютно сложного. Потому что я могу понять это, и я уверен, что другие тоже могут. Это
В чем проблема?Тогда я наконец нашел ответ. Мой вывод состоит в том, что любой, кто обучает продвинутым понятиям, должен
Начните с того, что он уже знает. Если процесс обучения доставляет удовольствие, а содержание обучения хорошо выражено, новые концепции будут
становится вполне интуитивным. Это мой ответ. Так называемое метапрограммирование, так называемая интеграция данных и кодовых форм, так называемая самомодифицирующаяся генерация
коды, так называемые подъязыки для конкретных приложений, все эти понятия являются принципиально родственными понятиями, объясняющими друг друга
Чем больше я не понимаю. Полезнее всего начать с практического примера.
Я рассказываю свои мысли программистам на Лиспе, выступили против них. «Конечно, эти вещи сами по себе не могут быть
знания, эти понятия настолько различны, что в имеющемся опыте других людей нельзя найти ничего похожего»,
Но я думаю, что это все отговорки. Они спросили меня в ответ: «Почему бы тебе не попробовать самому?» Что ж, я попробую.
Эта статья — результат моей попытки. Я собираюсь объяснить Лисп знакомым и интуитивно понятным способом, и я надеюсь, что кто-то, у кого хватит мужества прочитать его
Закончите, выпейте, сделайте глубокий вдох и приготовьтесь к головокружению. Приходите, пусть у вас будет сила.
Возвращаясь к XML
Тысяча миль начинается с одного шага. Давайте начнем с XML в качестве нашего первого шага. Но XML сказал больше, что еще
А как же новый смысл? Да. О самом XML говорить неинтересно, но отношения между XML и Lisp довольно интересны.
Существует поразительное сходство между концепциями XML и Lisp. XML — это наш мост к пониманию Lisp. Ну положим
XML как живое лекарство для лошадей. Давайте возьмем трость и исследуем нетронутую пустыню XML. мы начнем
Новый взгляд на тему.
На первый взгляд, XML — это стандартизированный синтаксис для выражения произвольных иерархических данных в удобочитаемом формате.
(иерархические данные). Например, списки дел, веб-страницы, медицинские записи, полисы автострахования, профили и т. д.
И т.д., где XML вступает в игру. Например, возьмем для примера таблицу задач:
<todo name="housework">
<item priority="high">Clean the house.</item>
<item priority="medium">Wash the dishes.</item>
<item priority="medium">Buy more soap.</item>
</todo>
Что происходит, когда эти данные анализируются? Как проанализированные данные представлены в памяти? Очевидно, представлены в виде дерева
Эти иерархические данные подходят. В конце концов, XML, относительно легкий для чтения формат данных, имеет древовидную структуру.
Результат после сериализации данных. Любые данные, которые могут быть представлены в виде дерева, также могут быть представлены в XML, и наоборот.
То же самое справедливо. Я надеюсь, вы понимаете это, это чрезвычайно важно для дальнейшего.
Сделайте еще один шаг вперед. Какие другие типы данных также обычно представляются деревьями? Несомненно, список также является типом. взял урок компиляции
Верно? Помните немного смутно? Исходный код также хранится в древовидной структуре после синтаксического анализа, и любая скомпилированная программа будет
Исходный код будет проанализирован в абстрактное синтаксическое дерево, что уместно, поскольку исходный код иерархичен:
Функции содержат параметры и блоки кода, блоки кода содержат выражения и операторы, операторы содержат переменные и операторы и так далее.
Мы уже знаем, что любую древовидную структуру можно легко записать в виде XML, и любой код будет разобран на дерево, поэтому,
Любой код можно преобразовать в XML, не так ли? Приведу пример, посмотрите на функцию ниже:
int add(int arg1, int arg2)
{
return arg1+arg2;
}
Можно ли преобразовать эту функцию в эквивалентный формат XML? Мы можем сделать это несколькими способами, вот как
Один из них, очень простой:
<define-function return-type="int" name="add">
<arguments>
<argument type="int">arg1</argument>
<argument type="int">arg2</argument>
</arguments>
<body>
<return>
<add value1="arg1" value2="arg2" />
</return>
</body>
</define>
Этот пример настолько прост, что не имеет значения, какой язык вы используете для его выполнения. Мы можем конвертировать любой программный код в XML,
Также можно преобразовать XML обратно в исходный код. Мы можем написать конвертер для преобразования кода Java в XML, еще один
Преобразователь преобразует XML обратно в Java. По той же причине этот метод можно использовать и против C++ (это почти безумие).
как. Но кто-то это делает, взгляните на GCC-XML (www.gccxml.org) знать). Дальше,
Все языки с одинаковыми языковыми функциями, но разным синтаксисом могут использовать XML в качестве посредника для преобразования кодов друг в друга. Фактически
Почти все основные языки в той или иной степени соответствуют этому условию. Мы можем использовать XML в качестве промежуточного представления,
Декодируйте друг друга между двумя языками. Например, Мы можем использовать Java2XML для преобразования кода Java в XML, а затем использовать
XML2CPP затем преобразует XML в код C++, если повезет, то есть, если мы будем осторожны, чтобы избежать использования этих C++ кодов.
С функциями Java мы можем получить полную программу на C++. Как насчет этого, красотка?
Все это в полной мере показывает, что мы можем использовать XML как общий метод хранения исходного кода, по сути, мы можем генерировать целый набор
Используя язык программирования с унифицированным синтаксисом, можно также написать преобразователи для преобразования существующего кода в формат XML. Если вы действительно принимаете
Таким образом, компиляторам различных языков не нужно писать собственный разбор грамматики, Их можно анализировать напрямую, используя синтаксис XML.
синтаксический анализ для прямого создания абстрактного синтаксического дерева.
Здесь вы должны спросить, мы давно изучаем XML, какое это имеет отношение к Лиспу?В конце концов, когда появился XML,
Лисп существует уже тридцать лет. Здесь я могу гарантировать, что вы поймете в кратчайшие сроки. Но прежде чем продолжить объяснение, я
Сначала сделаем небольшое упражнение на мышление. Взгляните на XML-версию примера функции добавления выше, как вы можете классифицировать его,
Что это: код или данные? Чтобы понять это, не нужно много думать, и имеет смысл отнести их к любой из этих категорий. это XML, это
данные стандартного формата. Мы также знаем, что его можно сгенерировать из древовидной структуры в памяти (это то, что делает GCC-XML).
Привязанность). Он сохраняется в неисполняемом файле. Мы можем разобрать его на узлы дерева, Затем выполните произвольные преобразования. показывать
И легко увидеть, что это данные. Но подождите, хотя его синтаксис немного незнаком, это действительно функция добавления,
Верно?После анализа он готов к компиляции и выполнению компилятором. Мы можем легко написать этот XML
интерпретатор кода и запустить его напрямую. Или мы можем перевести его в код Java или C++, а затем скомпилировать и запустить.
Ряд. Значит, это тоже код.
Где мы это сказали? Ну, мы нашли интересный ключевой момент. Понятия, которые раньше считались трудными для понимания
Это было очень интуитивно и очень просто показать. Код — это тоже данные, и всегда им был. это звучит безумно
безумный, На самом деле это неизбежно. Я обещал объяснить Лисп по-новому, и повторяю свое обещание.
обещать. Но мы еще не достигли заранее определенного места, поэтому давайте сначала продолжим обсуждение выше.
Я только что сказал, что мы можем очень просто реализовать XML-версию интерпретатора функции добавления, что звучит так, будто это просто разговор.
Вот и все. Кто на самом деле будет этим заниматься?Немногие воспримут это всерьез. Скажи это небрежно, не собираясь
Если вы захотите это сделать, вы можете столкнуться с таким явлением в своей жизни. Вы знаете, что я имею в виду, я имею в виду
Впечатлить вас? Вот вау, все в порядке, идем дальше.
Возвращаясь к муравью
Мы подошли к освещенной сзади стороне Луны, Не спешите уходить. Исследуйте немного больше и посмотрите, что еще мы можем найти
какие. Закройте глаза и подумайте о той дождливой ночи зимой 2000 года, о человеке по имени Джеймс Дункан Дэвидсон.
Блестящие программисты работают над контейнером сервлетов Tomcat. В то время он бережно хранил только что отредактированный текст.
файл, а затем выполнить make. Оказалась целая куча ошибок, явно что-то не так. После тщательного осмотра он
Думаете, это из-за того, что перед табом стоит пробел и команда не может быть выполнена? всегда, он действительно
достаточно. Луна за темными тучами дала ему просветление, Он создал новый проект Java, а затем написал простой
Но очень полезный инструмент, который ловко использует информацию в файле свойств Java для построения проекта, и теперь
Джеймс мог бы написать альтернативу make-файлам, которая служила бы той же цели, но в более элегантной форме, не беспокоясь о том, что
Ненавистная проблема с пробелами, такая как makefile. Этот инструмент может автоматически интерпретировать файл свойств, а затем предпринимать правильные действия для
Скомпилируйте проект. Это так просто и красиво.
(Примечание автора: я не знаю Джеймса, и Джеймс не знает меня, эта история основана на онлайн-посте об истории Муравейника.
сфабриковано)
Через несколько месяцев после создания Tomcat с Ant, Он все больше чувствовал, что файлов свойств Java недостаточно для выражения сложных инструкций по построению.
сделать. Файл необходимо извлечь, скопировать, скомпилировать, отправить на другую машину и протестировать. Если есть ошибка, отправьте электронное письмо
передать соответствующему персоналу и, в случае успеха, приступить к строительству максимально возможного объема. проследить до конца,
возвращается к исходному уровню. Действительно, файлов свойств Java недостаточно, Джеймсу нужно более гибкое решение.
строить планы. Он не хочет писать свой собственный синтаксический анализатор (потому что он предпочел бы стандартное решение). XML выглядит как
Хороший выбор. Ему потребовалось несколько дней, чтобы перенести Ant на XML, и родился отличный инструмент.
Как работает Муравей? Принцип очень прост. Ant преобразует XML-файлы, содержащие команды построения (либо код, либо данные,
Подумайте сами), передать Java-программу для анализа каждого элемента, на самом деле это намного проще, чем я сказал.
Простая инструкция XML заставит класс Java с тем же именем загрузить и выполнить свой код.
<copy todir="../new/dir">
<fileset dir="src_dir" />
</copy>
Смысл этого текста в том, чтобы скопировать исходный каталог в целевой каталог, и Ant найдет задачу «копирования» (на самом деле
Java), задайте соответствующие параметры (todir и набор файлов), вызвав метод Java, а затем выполните задачу.
Ant поставляется с набором основных классов, Он может быть произвольно расширен пользователем при соблюдении нескольких соглашений. Муравей находит эти классы,
Всякий раз, когда встречается элемент XML с тем же именем, выполняется соответствующий код. Процесс очень прост. Муравей сделал это раньше нас
Что он говорит: это интерпретатор языка, который использует XML в качестве синтаксиса и переводит элементы XML в соответствующие инструкции Java.
Мы можем написать задачу «добавить», а затем, когда найдем описание добавления в XML, выполнить задачу добавления.
Поскольку Ant — очень популярный проект, показанная ранее стратегия более разумна. Ведь это средство почти каждый день
Тысячи компаний используют его.
слишком далеко, Я ничего не сказал о трудностях, с которыми Ant сталкивается при анализе XML. Вам не нужно заходить на его сайт, чтобы найти ответ
случае, ничего ценного не будет найдено. По крайней мере, для нашей диссертации. Переходим к следующему шагу
Обсуждать. Наш ответ там.
Почему XML
Иногда правильное решение не совсем обдуманно. Я не знаю, выбрал ли Джеймс XML случайно. также
Возможно, это было просто подсознательное решение. По крайней мере, из того, что Джеймс написал на сайте Ant, его рассуждения полны
Это все показное. Его основные причины - переносимость и расширяемость, в случае с Ant я не вижу разницы между этими двумя
помощь. использовать XML вместо кода Java, В чем польза? Почему бы не написать набор классов Java, предоставляющих API для заполнения
достаточно базовых задач (копирование каталогов, компиляция и т. д.), а затем вызывать код непосредственно на Java?
Нет сомнений в переносимости и масштабируемости. Да и грамматика более привычна и приятна глазу. Так зачем использовать XML
Какая лучшая причина?
немного. Хотя я не уверен, понимает ли это Джеймс. С точки зрения семантической конструктивности XML так же устойчив, как и Java.
Недостижимый. Не хочу пугать вас непонятными терминами, рассуждения достаточно просты и легко объяснимы
Много усилий. хорошо, С приготовлениями на месте, мы собираемся совершить резкий скачок к моменту прозрения.
Как реализовать приведенный выше пример копирования в коде Java?Мы можем сделать это:
CopyTask copy = new CopyTask();
Fileset fileset = new Fileset();
fileset.setDir("src_dir");
copy.setToDir("../new/dir");
copy.setFileset(fileset);
copy.excute();
Этот код очень похож на код XML, Просто немного дольше. В чем разница? Разница в том, что конструкции XML
Специальный глагол копирования, если бы нам пришлось писать его на Java, выглядел бы так:
copy("../new/dir");
{
fileset("src_dir");
}
Увидеть разницу? Приведенный выше код (если его можно использовать в Java) представляет собой специальный оператор копирования, немного похожий на
цикл for или цикл foreach в Java5. Если бы у нас был конвертер, который мог бы преобразовывать XML в Java, было бы здорово
Вы, вероятно, получите приведенный выше фрагмент кода, который на самом деле не является исполняемым. Поскольку технические спецификации Java мертвы, мы не
способ изменить его в программе. Мы можем добавлять пакеты, добавлять классы, добавлять методы, но мы не можем добавлять операторы,
А с XML мы, очевидно, можем сами добавлять такие вещи. Для синтаксического дерева XML, если исходное значение,
Мы можем добавить любой элемент произвольно, Таким образом, мы можем добавлять операторы произвольно. Если вы все еще не понимаете,
Взгляните на следующий пример, добавив, что мы хотим ввести оператор «если» в Java:
unless(someObject.canFly())
{
someObject.transportByGround():
}
В двух приведенных выше примерах Мы собираемся расширить грамматику Java двумя операторами: оператором группового копирования файла и условным оператором.
если мы хотим сделать это, мы должны изменить абстрактное синтаксическое дерево, которое может принять компилятор Java, очевидно, мы
Невозможно сделать это со стандартной функциональностью Java. Но в XML мы можем сделать это легко. наш парсер
По элементу XML генерируется абстрактное синтаксическое дерево, а из него генерируется оператор, так что мы можем произвольно ввести любой оператор.
Для сложных операторов преимущества этого очевидны. Например, используйте определенный оператор, чтобы проверить исходный код, скомпилировать
файлы, модульные тесты, отправка электронных писем и другие задачи, Подумайте, как это прекрасно. Для определенных тем, таких как создание мягких
Элементы, использование этих операторов может значительно сократить объем кода. Повысьте ясность кода и возможность его повторного использования.
Интерпретируемый XML может легко достичь этой цели. XML — это простой файл данных для хранения иерархических данных.
В Java, поскольку иерархии фиксированы (как вы скоро увидите, Лисп сильно отличается), мы не
способ достижения вышеуказанных целей. Возможно, именно это делает Ant таким успешным.
Вы можете обратить внимание на последние изменения в Java и C# (особенно на техническую спецификацию C# 3.0), C# абстрагирует часто используемые функции
Приходить, Добавлен в C# как оператор. В качестве примера можно привести недавно добавленный в C# оператор запроса. Он по-прежнему использует традиционный метод:
Разработчики C# модифицируют абстрактное синтаксическое дерево, а затем добавляют соответствующую реализацию. Если программист сам может модифицировать абстрактное синтаксическое дерево
Как здорово!Таким образом мы можем создавать подъязыки для конкретных задач (например, как Ant для построения проектов)
язык), можете ли вы придумать другие примеры? Подумайте еще раз о концепции. Но не думайте слишком много, мы увидим
Вернусь к этой теме. Тогда будет понятнее.
Приближаемся к Lisp
Давайте на мгновение отложим в сторону оператор и рассмотрим что-то, выходящее за рамки конструктивных ограничений Ant. Я сказал ранее, Муравей может пройти
Расширьте, написав классы Java. Синтаксический анализатор Ant сопоставляет элементы XML и классы Java по имени и, как только совпадение найдено, выполняет
выполнить соответствующее задание. Почему бы не расширить Ant самостоятельно?В конце концов, основная задача включает в себя множество традиционных языковых конструкций.
(например, «если»), если Ant сам предоставляет возможность создавать задачи (вместо того, чтобы полагаться на классы Java), мы можем получить
к более высокой переносимости. Мы будем полагаться на основной набор задач (или назовем его стандартной библиотекой, если вы это имеете в виду) и
Неважно, есть у вас среда Java или нет. Этот набор основных задач может быть достигнут любым способом, в то время как другие задачи строятся здесь.
Помимо основных задач группы, Таким образом, Ant станет расширяемым языком программирования общего назначения на основе XML. рассмотреть возможность
Возможность следующего кода:
<task name="Test">
<echo message="Hello World" />
</task>
<Test />
Если XML поддерживает создание «задачи», приведенный выше код выведет «Hello World!» На самом деле мы можем
Напишите задачу «задача» на Java, а затем расширьте ее с помощью Ant-XML. Муравей может написать более сложное на основе простых примитивов
Разные примитивы, как это принято в других языках программирования. Это программирование на основе XML, о котором мы упоминали в начале.
язык программирования. Это не очень полезно (знаете почему?), но это действительно круто.
Посмотрите еще раз на задачу Task, о которой мы только что говорили. Поздравляю, вы смотрите код на Лиспе!!! Что я говорю? Ничего подобного
Lisp?Неважно, давайте немного почистим его.
лучше, чем XML
Как упоминалось в предыдущем разделе, саморасширение Ant не очень полезно, поскольку XML громоздок. Для данных проблема
Не слишком большой, но если код громоздкий, одна только проблема с набором текста может с лихвой компенсировать его преимущества. ты написал Муравей
Сценарии Я уже писал, что XML очень раздражает, когда сценарии достигают определенного уровня сложности. Подумайте об этом, ибо
Пишите закрывающие теги, вводите каждое слово дважды, не сходите с ума!
Чтобы решить эту проблему, мы должны упростить написание. Уведомление, XML — это всего лишь способ выражения иерархических данных.
Нам не нужно использовать угловые скобки, чтобы получить сериализованный результат дерева. Мы можем использовать совершенно другие форматы.
Один из этих форматов (который используется Лиспом) называется s-выражением. s-выражения делают то же самое, что и XML, но
Его преимущество в том, что метод записи проще, а простой метод записи больше подходит для ввода кода. Я расскажу больше о s-выражениях позже. Перед этим
Я собираюсь очистить материал XML. Рассмотрим пример с копированием файлов:
<copy toDir="../new/dir">
<fileset dir="src_dir">
</copy>
Подумайте, как будет выглядеть в памяти дерево разбора этого кода, там будет узел «копировать», под которым
Узел "набор файлов" есть, но где атрибут? Как он выражается? Если вы раньше работали с XML и
Если вы не знаете, использовать ли элементы или атрибуты, вы не должны чувствовать себя одинокими, такими же запутанными, как и все остальные. Никто действительно не понимает
Чу. Этот выбор основан не столько на технических причинах, сколько на слепых. Концептуально, свойства также
Является элементом, любой атрибут может сделать, элемент может сделать то же самое. Причина, по которой XML вводит атрибуты, на самом деле состоит в том, чтобы сделать
Нотация XML менее подробна. Например, давайте рассмотрим пример:
<copy>
<toDir>../new/dir</toDir>
<fileset>
<dir>src_dir</dir>
</fileset>
</copy>
Сравните два, Объем информации в содержимом точно такой же, а объем ввода можно уменьшить с помощью атрибутов. Если XML не имеет атрибутов,
Достаточно просто напечатать, чтобы свести людей с ума.
Поговорив о проблеме атрибутов, давайте взглянем на s-выражение. Причина такого изгиба в том, что s-выражение не имеет атрибута
концепция сексуальности. Поскольку s-выражения очень лаконичны, нет необходимости вводить атрибуты. Мы конвертируем XML в s-выражения
Когда вы это сделаете, вы должны помнить об этом. В качестве примера приведенный выше код преобразуется в s-выражение следующим образом:
(copy
(todir "../new/dir")
(fileset (dir "src_dir")))
Посмотрите внимательно на этот пример, в чем разница, угловые скобки заменены скобками, а каждый элемент изначально отмечен парой скобок
Окруженный, теперь последняя скобка (то есть та, что со слэшем) удалена. Только ")" требуется для обозначения конца элемента
Вот и все. Ну, это отличия. Преобразование этих двух выражений очень естественно и очень просто. стабильный
Кроме того, Да Ши намного легче печатать. Глядя на s-выражения (Lisp) в первый раз, Скобки раздражают, не так ли? Теперь мы знаем
Когда причина, стоящая за этим, проясняется, становится намного легче. По крайней мере, намного лучше, чем XML. писать код с s-выражениями, нет
Это просто практично, но и очень приятно. s-выражения обладают всеми преимуществами XML, которые мы только что обсуждали.
из. Теперь давайте посмотрим на пример задачи в стиле Лиспа:
(task (name "Test")
(echo (message "Hellow World!")))
(Test)
На жаргоне Лиспа s-выражения называются списками. Для приведенного выше примера, если мы напишем без изменения
строки, с запятыми вместо пробелов, выражение очень похоже на список элементов с вложенными
он отметил.
(task, (name, "test"), (echo, (message, "Hello World!")))
XML, естественно, также может быть написан в этом стиле. Конечно, приведенное выше предложение не является таблицей элементов в общем смысле. это на самом деле
это дерево. Это то же самое, что и XML. назвать это списком, Надеюсь, вы не запутались, потому что вложенные таблицы и
На самом деле деревья — это одно и то же. Лисп буквально означает обработку списка, на самом деле его также можно назвать деревом.
обработки, которая ничем не отличается от обработки XML-узлов.
После всех этих мучений мы теперь, наконец, довольно близко подошли к Лиспу, к загадочной природе лисповских скобок (как и во многих других случаях).
Фанатики Лиспа думали) постепенно появился. Теперь переходим к другим вещам.
Пересмотр макросов на языке C
На данный момент вы, вероятно, устали слушать обсуждение XML, а я устал говорить об этом. Остановимся ненадолго, поставим елку, s-выражение,
Сначала поместите эти вещи в Ant, давайте поговорим о препроцессоре C. Кто-то наверняка спрашивал, какое отношение наша тема имеет к C
Отношения?Мы уже много знаем о метапрограммировании, и мы говорили о специально написанном коде. понять проблему
Существует определенная степень сложности, поскольку все языки программирования, используемые в соответствующих дискуссионных статьях, вам незнакомы. Но если только в целом
Если вы читаете это, это относительно просто. Я считаю, что если мы используем язык C в качестве примера для обсуждения метапрограммирования, мы его поймем.
было бы намного проще. Хорошо, продолжим.
Один вопрос-зачем код писать код?В реальном программировании как это сделать? Дэюань
Что такое программирование?Вы наверняка слышали ответы на эти вопросы, но не знаете почему. раскрыть
Истина позади, давайте рассмотрим простую задачу запроса базы данных. Мы сделали такую вещь. Например,
Очень раздражает писать операторы SQL прямо в коде программы для изменения данных в таблице. даже использовать
C# 3.0 LINQ, все еще не менее болезненный. Напишите полный SQL-запрос (хотя и с хорошим синтаксисом), чтобы изменить чье-то местоположение.
адрес или поиск чьего-то имени определенно утомительны для программистов, так как же мы решим эту проблему?
Вопрос? Ответ: Используйте уровень доступа к данным.
Концепция довольно проста, главное — абстрагировать содержимое доступа к данным (по крайней мере, более тривиальные части), использовать классы для
Сопоставьте таблицы базы данных, а затем используйте метод доступа к объектному свойству доступа (accessor) для косвенной реализации запроса. так что
Значительно упрощает работу по разработке. Мы используем методы для доступа к объектам (или присвоения свойств, в зависимости от выбранного вами языка).
) вместо написания SQL-запросов. Любой, кто использовал этот метод, знает, что он экономит время. Конечно, если
Вы должны сами написать такой уровень абстракции, что занимает много времени — вам нужно написать набор классов для сопоставления таблицы,
Сексуальный доступ преобразуется в SQL-запрос, Эта жизнь довольно утомительна. Очевидно, что делать это вручную неразумно. Но однажды
Когда у вас есть схема и шаблон, вам особо не о чем думать. Вам просто нужно следовать одному и тому же шаблону снова и снова.
Просто пишите похожий код снова и снова. На самом деле многие люди нашли лучший способ, есть некоторые инструменты, которые могут
Помогает вам подключиться к базе данных, получить определение схемы базы данных и следовать предопределенным или определенным пользователем шаблонам.
Писать код автоматически.
Если вы пользовались этим средством, вас обязательно впечатлит его магический эффект. Часто для этого требуется всего несколько щелчков мышью.
Может подключаться к базе данных, генерировать исходный код доступа к данным, Затем добавьте файл в свой проект, десять минут работы
Если работа выполняется вручную, на ее выполнение могут уйти сотни человеко-часов. Но,
Что делать, если определение структуры вашей базы данных изменится позже?В этом случае вы можете просто повторить процесс
к. Есть даже инструменты, которые автоматизируют это изменение. Вы просто используете его как часть инженерной конструкции, каждый
Когда проект компилируется в следующий раз, часть базы данных также автоматически реструктурируется. Это действительно потрясающе. В основном, что вы должны сделать
снизился до 0. Если определение структуры базы данных изменяется, а код уровня доступа к данным автоматически обновляется во время компиляции,
то любое место в программе, где используется устаревший старый код, вызовет ошибки компиляции.
Слой доступа к данным — хороший пример, и есть еще много других. Стандартный код из GUI, WEB-кода, COM и
Заглушки CORBA, а также MFC и ATL и т. д. В этих местах много одинаковых кодов, многократно повторяющихся. Поскольку эти
Код может быть написан автоматически, а время программиста намного дороже, чем время процессора, конечно, многие инструменты берутся из
Автоматически генерировать шаблонный код. Какова природа этих инструментов? На самом деле это программы, которые создают программы. у них есть
Таинственное имя под названием метапрограммирование. Вот что такое метапрограммирование.
Метапрограммирование можно было бы использовать в бесчисленном количестве мест, Но на практике он используется не так часто. Ведь мы
Я все еще думаю об этом, предполагая, что повторяющийся код копируется и вставляется, он будет повторяться примерно 6 или 7 раз.Для такой нагрузки
Стоит ли создавать специальный набор инструментов для сборки? Уровни доступа к данным и COM-заглушки часто необходимо повторно использовать сотни раз.
Даже тысячи раз, поэтому генерация с помощью инструментов — лучший способ. А те коды, которые повторяются всего несколько раз или дюжину раз, не являются
Необходимо изготовить специальные инструменты. Разрабатывать инструменты генерации кода, когда в этом нет необходимости, явно переоценивать генерацию кода.
в преимущества. Конечно, если создать такой инструмент достаточно просто, его следует использовать как можно чаще, потому что это
сэкономит время. Теперь давайте посмотрим, есть ли разумный способ добиться этого.
Сейчас, Препроцессор Си пригодится. Мы все использовали препроцессор C/C++, который мы используем для выполнения простой компиляции.
инструкции, для создания простых преобразований кода (например, для установки переключателя кода отладки), см. пример:
#define triple(X) X+X+X
Что делает эта строка? Это простая предварительно скомпилированная директива, которая вызывает тройную (X) подстановку в программе как
Х+Х+Х. Например, замените все тройные (5) на 5+5+5, а затем передайте их компилятору для компиляции. это просто
Простой пример генерации кода. Если бы препроцессор C был более мощным, Если вы можете разрешить подключение к базе данных, если вы можете
С помощью некоторых других простых механизмов мы можем разработать собственный уровень доступа к данным внутри нашей программы. последующий
Пример, гипотетическое расширение макроса C:
#get-db-schema("127.0.0.1")
#iterate-through-tables
#for-each-table
class #table-name
{
};
#end-for-each
Мы подключаем определение структуры базы данных, просматриваем таблицы данных и создаем класс для каждой таблицы, Сделано всего в нескольких строках кода
эта работа. Таким образом, каждый раз при компиляции проекта эти классы будут синхронно обновляться в соответствии с определением базы данных. очевидный
Видите ли, мы построили полный уровень доступа к данным внутри программы, не напрягаясь, без каких-либо внешних
инструмент. Конечно, у этого подхода есть недостаток, заключающийся в том, что нам нужно изучать новый «язык времени компиляции», еще один недостаток
Такой продвинутой версии препроцессора Си просто нет. Когда требуется генерация сложного кода, этот язык (перевод
Примечание редактора: это относится к директивам предварительной обработки, которые сами авторы называют «языками времени компиляции»), которые неизбежно становятся довольно сложными. Это
Необходимо поддерживать достаточное количество библиотек и языковых конструкций. Например, код, который мы хотим сгенерировать, зависит от некоторых ftp-серверов.
документ, Препроцессор должен будет поддерживать доступ по ftp, создавая и изучая новый язык только для этой задачи.
Это как-то отвратительно (то, что уже есть языки, способные на это, еще более абсурдно). Мы могли бы также
Чтобы быть гибкими, почему бы просто не использовать C/C++ в качестве собственного языка предварительной обработки?
Чтобы проявить мощную способность языка, новые вещи, которые нужно изучить, — это всего лишь несколько простых указателей, которые используются для
Различайте код времени компиляции и код времени выполнения.
<%
cout<<"Enter a number: ";
cin>>n;
%>
for(int i=0;i< <% n %>;i++)
{
cout<<"hello"<<endl;
}
Ты понимаешь это? Код между тегами <% %> запускается во время компиляции, другой код вне тегов является нормальным
код. При компиляции программы вам будет предложено ввести число, которое будет использоваться в дальнейшем в цикле. в то время как цикл
Код для кольца будет скомпилирован. Предполагая, что вы ввели 5 во время компиляции, код цикла for будет таким:
for(int i=0;i<5; i++)
{
cout<<"hello"<<endl;
}
простой и эффективный, Также нет необходимости в дополнительном языке предварительной обработки. Мы можем воспользоваться основным языком во время компиляции (
Вот сила C/C++), мы можем легко подключиться к базе данных во время компиляции, установить уровень доступа к данным, просто
Создавайте веб-страницы, такие как JSP или ASP. Нам также не нужны специальные оконные инструменты для создания дополнительных проектов. мы можем
В код сразу добавляются необходимые инструменты. Нам также не нужно беспокоиться о том, стоит ли создавать такой инструмент, потому что это слишком просто.
, это слишком просто. Я не знаю, сколько времени это может сэкономить.
Привет Лисп
Инструкции, которые мы знаем о Лиспе до сих пор, можно суммировать в одном предложении: Lisp — это исполняемый синтаксис.
Красивый XML, но мы еще не сказали, как это делает Lisp, давайте перейдем к этой теме.
Лисп имеет множество встроенных типов данных, а целые числа и строки ничем не отличаются от других языков. вроде 71 или
Такое значение, как «привет», имеет примерно то же значение, что и в таких языках, как C++ или Java. Три типа, которые действительно интересны, это
Символы, таблицы и функции. Оставшаяся часть этой главы будет посвящена знакомству с этими типами, а также
Как среда Lisp компилирует и запускает исходный код. Этот процесс обычно называется оценкой в терминах Лиспа. прочитайте это
содержание раздела, Для полного понимания истинного потенциала метапрограммирования, идентичности кода и данных и предметно-ориентированного языка.
Понятия чрезвычайно важны. Не относитесь к этому легкомысленно. Я постараюсь быть более живым и интересным, и я надеюсь, что вы можете получить некоторые
Вдохновленный. Ну, давайте сначала поговорим о символах.
В общем, символы эквивалентны идентификаторам в C++ или Java, и их имена можно использовать для доступа к значениям переменных (например,
currentTime, arrayCount, n и т. д.), разница в том, что нотация в Лиспе более проста. на С++ или
В Java в именах переменных может использоваться только комбинация букв и символов подчеркивания, в то время как символы в Лиспе очень содержательны. Например, добавить
Знак (+) является допустимым символом, другие, такие как -, =, hello-world, * и т. д., могут быть именами символов. символ
Правила именования имен можно найти в Интернете. Этим символам можно присвоить любое значение, сначала мы используем псевдокод, чтобы проиллюстрировать это.
немного. Предполагая, что набор функций присваивает значение переменной (как знак равенства = в C++ и Java), вот наш пример:
set(test, 5) // значение символа test равно 5
установить (=, 5) // Значение символа = равно 5
set(test, "hello") // значением символа test является строка "hello"
set(test, =) // В настоящее время значение символа = равно 5, поэтому значение test также равно 5
set(*, "hello") // значение символа * равно "hello"
Кажется, что-то не так? Предположим, мы присваиваем * целочисленному или строковому значению, как насчет умножения? Независимо от того
Как сказать, *всегда умножается?Ответ прост. Роль функций в Лиспе очень особенная, функции также являются разновидностью данных.
тип, например целые числа и строки, поэтому его можно назначать символам. Функция умножения Встроенная функция Лиспа, по умолчанию
Вместо присваивания * вы можете присвоить * другие функции, чтобы * не представляла умножение. Вы также можете сохранить значение этой функции
в другую переменную. Давайте используем псевдокод для иллюстрации:
*(3,4) // 3 раза по 4, результат 12
заданная температура, *) // Присвоить значение *, которое является функцией умножения, временной
set(*, 3) // присвоить 3 *
*(3,4) // неправильное выражение, * это уже не умножение, а значение 3
temp(3,4) // temp — это функция умножения, поэтому значение этого выражения 3 умножить на 4 равно 12
set(*, temp) // снова присваиваем функцию умножения *
*(3,4) // 3 умножить на 4 равно 12
Чтобы стать немного страннее, присвойте значение знака минус знаку плюс:
set(+, -) // минус (-) — это встроенная функция вычитания
+(5, 4) // Знак плюс (+) теперь является функцией вычитания, результат 5 минус 4 равно 1
Это всего лишь пример, я еще не рассматривал функции подробно. Функция в Лиспе — это тип данных, а также целые числа, строки,
символы и так далее. Функция не обязательно имеет имя, что сильно отличается от ситуации в C++ или Java.
Здесь сама функция представляет себя. Фактически это указатель на блок кода, с дополнительной информацией (например,
например, набор переменных параметров). Функция имеет имя только тогда, когда она назначена другому символу, например присвоению числа или
Строки присваиваются переменным таким же образом. Вы можете создавать функции с помощью встроенной специальной функции для создания функций,
Затем присвойте его символу fn, который выражается в псевдокоде как:
fn [a]
{
return *(a, 2);
}
Этот код возвращает функцию с одним параметром, и функция функции состоит в том, чтобы вычислить результат умножения параметра на 2. Эта функция также
Без имени вы можете назначить эту функцию другому символу:
set(times-two, fn [a] {return *(a, 2)})
Теперь мы можем вызвать эту функцию следующим образом:
раз-два(5) // вернуть 10
Давайте сначала пропустим символы и функции и поговорим о таблицах. Что такое часы Возможно, вы много слышали об этом. Таблица I
Одним словом, это использование s-выражения для представления блоков данных, таких как XML. Таблица заключена в пару круглых скобок, элемент в таблице
Элементы разделяются пробелами, а таблицы могут быть вложенными. Например (на этот раз мы используем настоящий синтаксис Lisp, обратите внимание на точку с запятой для комментариев):
() ; пустая таблица
(1) ; список с одним элементом
(1 "test") ; таблица из двух элементов, один элемент - целое число 1, другой - строка
(тест "hello"); двухэлементная таблица, один элемент — символ, другой — строка
(тест (1 2) "привет"); таблица из трех элементов, тест символов, таблица с двумя элементами 1 и 2
; таблица, последний элемент — строка
Когда система Лиспа встречает такую таблицу, она делает то же самое, что Ant делает с XML-данными, то есть пытается
Граф выполняет их. На самом деле исходный код Lisp — это особый вид таблицы, точно так же, как исходный код Ant — это особый вид XML.
Порядок, в котором Лисп выполняет таблицу, таков, что первый элемент таблицы используется как функция, а остальные элементы используются как параметры функции. если
Один из параметров также является таблицей, далее таблица оценивается по тому же принципу, и результат передается исходной функции как
параметр. Это основной принцип. Давайте посмотрим на реальный код:
(* 3 4) ; Эквивалентно приведенному выше псевдокоду*(3,4), который вычисляет 3 раза 4
(times-two 5) ; return 10, times-two — это 2-кратный параметр согласно предыдущему определению
(3 4) ; ошибка, 3 не является функцией
(раз-два) ; ошибка, раз-два требует аргумент
(раз-два 3 4) ; ошибка, раз-два требуется только один аргумент
(набор +-) ; назначаем функцию вычитания знаку +
(+ 5 4) ; В соответствии с результатом предыдущего предложения, в это время + означает вычитание, поэтому верните 1
(* 3 (+ 2 2)) ; результат 2+2 будет 4, умножьте на 3, результат будет 12
В приведенном выше примере все таблицы обрабатываются как код. Как рассматривать таблицу как данные? такой же,
Представьте, что Ant принимает XML-данные в качестве своих параметров. В Лиспе мы ставим перед таблицами префикс ' для обозначения чисел.
согласно с.
(set test '(1 2)) ; значение test представляет собой двухэлементный список
(установите тест (1 2)) ; ошибка, 1 не является функцией
(set test '(* 3 4)) ; значение test представляет собой таблицу из трех элементов, три элемента - *, 3, 4
Мы можем использовать встроенную функцию head, чтобы вернуть первый элемент таблицы, и функцию tail, чтобы вернуть остальные элементы.
поверхность.
(голова '(* 3 4)) ; символ возврата *
(хвост '(* 3 4)) ; вернуть таблицу (3 4)
(голова (тал '(* 3 4))) ; возвращает 3
(голова тест) ; вернуть *
Вы можете думать о встроенных функциях Лиспа как о задачах Ant. Разница в том, что нам не нужно расширять его на другом языке.
Lisp (хотя это можно сделать), мы можем расширить себя с помощью самого Lisp, как упомянутые выше раз-два.
Пример функции. Набор встроенных функций Лиспа очень компактен и содержит только самые необходимые части. Остальные функции есть
Реализовано для стандартной библиотеки.
Лисп-макрос
Мы уже видели применение метапрограммирования в механизме шаблонов, подобном JSP. Мы передаем простую строку
для генерации кода. Но мы можем сделать лучше. Давайте сначала зададим вопрос, Как написать инструмент, который находит
исходные файлы в структуре каталогов для автоматического создания скриптов Ant.
Создание скриптов Ant с помощью манипуляций со строками — простой способ. Конечно, есть и более абстрактные, выразительные
Более мощным и масштабируемым способом является использование библиотеки XML для непосредственной генерации узлов XML в памяти, чтобы в памяти
Узлы могут быть автоматически сериализованы в строки. Мало того, наш инструмент также может анализировать эти узлы,
Некоторые файлы XML выполняют преобразование. Непосредственно обрабатывая узлы XML. Мы можем выйти за рамки обработки строк и использовать более высокий уровень
концепция, поэтому наша работа будет выполняться быстрее и лучше.
Конечно, мы можем напрямую использовать сам Ant для преобразования XML и создания инструментов для генерации кода. Или мы также можем использовать Lisp
чтобы сделать эту работу. Как мы знали раньше, Таблицы — это структуры данных, встроенные в Лисп, а Лисп содержит ряд инструментов для
Быстрый и эффективный манипуляционный стол (голова и хвост — самые простые). Кроме того, в Лиспе нет семантических ограничений, вы можете построить
Любая структура данных, как вы хотите.
Lisp выполняет метапрограммирование с помощью макросов. Пишем набор макросов для преобразования списка дел в выделенный
язык домена.
Вспомните приведенный выше пример списка дел, формат данных XML выглядит следующим образом:
<todo name = "housework">
<item priority = "high">Clean the hose</item>
<item priority = "medium">Wash the dishes</item>
<item priority = "medium">Buy more soap</item>
</todo>
Соответствующее s-выражение таково:
(todo "housework"
(item (priority high) "Clean the house")
(item (priority medium) "Wash the dishes")
(item (priority medium) "Buy more soap"))
Предположим, мы хотим написать программу управления таблицей задач, сохраняя данные таблицы задач в набор файлов, когда программа запускается, из
Файл считывает эти данные и отображает их пользователю. Как бы эта задача решалась на других языках (скажем, на Java)?
Проанализирует файл XML, получит из него данные таблицы задач, Затем напишите код для обхода дерева XML и преобразования его в структуру данных Java.
(Честно говоря, парсинг XML в Java действительно непростая задача) и, наконец, представление данных пользователю. сейчас если
В Лиспе, как это сделать?
Предполагая, что мы будем использовать тот же ход мыслей, мы, вероятно, воспользуемся библиотекой Lisp для разбора XML. XML для нас — это Lisp
Таблица (s-выражение), мы можем просмотреть эту таблицу, а затем отправить соответствующие данные пользователю. Однако, поскольку мы используем
Lisp, нет необходимости сохранять данные в формате XML, просто используйте выражение s напрямую, поэтому нет необходимости делать
преобразован. Нам не нужна специальная библиотека синтаксического анализа, Lisp может обрабатывать s-выражения непосредственно в памяти. Примечание, Лисп
Компиляторы, как и компиляторы .net, всегда доступны во время выполнения программ на Лиспе.
Но есть лучший способ. Нам даже не нужно писать выражения для хранения данных, мы можем писать макросы, которые обрабатывают данные как прокси.
код для обработки. Итак, как это сделать? Напомним, формат вызова функции Лиспа:
(function-name arg1 arg2 arg3)
где каждый параметр представляет собой s-выражение после оценки, передается в функцию. Если мы заменим arg1 на (+ 4 5),
Затем программа сначала найдет результат, который равен 9, а затем передаст 9 в функцию. Макросы работают как функции. основной
Отличие в том, что параметры макроса не оцениваются при их подстановке.
(macro-name (+ 4 5))
Здесь (+ 4 5) передается макросу в виде таблицы, и макрос затем может произвольно обрабатывать таблицу и, конечно, также может ее оценивать.
стоимость. Возвращаемым значением макроса является таблица, после чего программа выполняется как код. Позиция, занятая макросом, заменяется этим
код результата. Мы можем определить макрос, чтобы заменить данные с произвольным кодом, Например, замените с отображением данных пользователю
код.
Какое отношение это имеет к метапрограммированию и программе списка задач, которую мы собираемся делать?На самом деле компилятор делает всю работу за нас,
Вызовите соответствующий макрос. Все, что нам нужно сделать, это создать макрос, который преобразует данные в соответствующий код.
Например, кубический макрос C, который я использовал выше, написанный на Лиспе, выглядит так:
(defmacro triple (x)
`(+ ~x ~x ~x))
(Аннотация: в Common Lisp одинарные кавычки здесь должны быть обратными одинарными кавычками, что означает, что таблица не оценивается, но может использоваться для
Чтобы оценить элемент в таблице, символ ~ означает оценку элемента x, и этот символ оценки должен быть запятой в Common Lisp.
Разница между обратными одинарными кавычками и одинарными кавычками заключается в том, что одинарная кавычка отмечает таблицу, и ни один из элементов в ней не оценивается. Примечание, использованное автором здесь
это придуманный мной диалект Лиспа Блез, который немного отличается от обычного шепелявости.
Единственная забава мастеров лиспа, и многие фанатики хотят этим заниматься. как Пол Грэм изобрел ARC, многие
Обозначение намного проще традиционного Лиспа и выглядит более современно)
Целью одинарных кавычек является подавление оценки таблицы. Каждый раз, когда в программе появляется тройка,
(triple 4)
будет заменено на:
(+ 4 4 4)
Мы можем написать макрос для программы таблицы задач, преобразовать данные задачи в исполняемый код и выполнить его. Предположим, мы теряем
out находится в консоли:
(defmacro item (priority note)
`(block
(print stdout tab "Prority: " ~(head (tail priority)) endl)
(print stdout tab "Note: " ~note endl endl)))
Мы создали очень маленький ограниченный язык для управления списками задач, встроенными в Лисп. Этот язык используется только для решения специальных
Проблемы, связанные с доменом, часто называют DSL (Domain-Specific Languages или Domain-Specific Languages).
язык домена
В этой статье рассказывается о двух предметно-ориентированных языках, один из которых — Ant, — который имеет дело с конструкциями программного обеспечения. Один безымянный, используется для обработки
список задач управления. Разница между ними заключается в том, что Ant построен с использованием XML, синтаксического анализатора XML и языка Java вместе.
из. А наш мини-язык полностью встроен в Лисп, Сделано всего за несколько минут.
Мы уже говорили о преимуществах DSL, поэтому Ant напрямую использует XML вместо Java. Если вы используете Лисп,
Мы можем создавать DSL столько, сколько захотим. Мы можем создать DSL для веб-программ, можем написать многопользовательский
игры, торговля с фиксированным доходом, решение проблем свертывания белка, решение деловых проблем и т. д.
Ждать. Мы можем сложить их вместе и создать язык, специально предназначенный для сетевых торговых процедур, как
Преимущества сетевого языка, а также преимущества торгового языка. Каждый день мы пожинаем плоды этого подхода, далеко
Больше, чем Ant может дать нам.
Используя DSL для решения проблем, получающиеся в результате программы оптимизированы, просты в обслуживании и гибки. В Java мы можем использовать классы для
решение вопросов. Разница между этими двумя подходами в том, что Lisp выводит нас на более высокий уровень абстракции, где мы больше не связаны
Ограничения самого языкового парсера, сравните скрипт построения, написанный непосредственно на библиотеке Java, и скрипт построения, написанный на Ant
разница. Опять же, сравните то, что вы делали раньше, и вы увидите преимущества Lisp.
следующий
Изучение Лиспа похоже на борьбу за холм на войне. Хотя в области информатики, Лисп уже является древним языком, пока
До сих пор очень немногие люди действительно понимают, как обучать Лиспу новичков. Несмотря на все усилия ветеранов Лиспа,
Изучение Лиспа сегодня по-прежнему сложно для новичков. К счастью, сейчас все меняется, и ресурсы Лиспа быстро растут.
Кроме того, со временем Lisp будет привлекать к себе все больше внимания.
Лисп позволяет людям выйти за рамки посредственности и выйти на передний план. Изучение Лиспа означает, что вы получите лучшую работу, потому что умные работодатели
Впечатлен вашей уникальной проницательностью. Изучение Лиспа может также означать, что завтра вас могут уволить, потому что вы всегда
подчеркивать, Если весь софт в компании написан на Лиспе, то какая замечательная будет компания, и вашим коллегам будет неприятно слышать эти слова.
Стоит ли изучать Лисп Те, кто изучал Лисп, говорят, что оно того стоит, конечно, судить вам.
Каково твое мнение?
Эта статья писалась и писалась, и на ее завершение ушло несколько месяцев. Если вы считаете это интересным, или у вас есть какие-либо вопросы, комментарии или
Для предложений, пожалуйста, напишите мне coffeemug@gmail.com, и я буду рад услышать ваши отзывы. подобно рекомендовать %>