Введение в Scheme

7edaa1629346427f8896aa8bbd84d6a1.png


Наиболее важным, но в то же время и наиболее незаметным свойством любого инструмента является его влияние на формирование привычек людей, которые имеют обыкновение им пользоваться.
Эдсгер Вайб Дейкстра

Введение


В практике программирования часто возникает потребность в написании небольших скриптов для автоматизации различных административных процессов, тестирования и мониторинга. Так же не редко появляется необходимость встроить какой-либо интерпретатор в приложение или просто создать прототип для проверки идеи. Для этих целей можно использовать различные популярные инструменты JavaScript, Python, Lua, Bash, BAT, PHP и много чего еще. А еще бывает потребность хранить структурированные данные в файлах или передавать по сети, когда речь идет о текстовых форматах обычно используются XML, JSON, CSV, даже KV. Однако несмотря на достоинства и распространенность таких широко известных инструментов меня не оставляла навязчивая идея поиска более гибкого и изящного средства. Таким образом, я однажды обратил внимание на семейство Lisp языков. И Lisp позволил застрелить сразу всех зайцев одним выстрелом, причем красиво и элегантно. Поскольку он имеет множество реализаций и стандартов под любые нужды и вкусы. Может выступать как в качестве самостоятельного языка, так и встраиваемого. Имеет единый формат представления данных и кода программы. А главное при необходимости написание собственного интерпретатора не является непосильной задачей.

Когда следует использовать Lisp, а когда нет? Этому вопросу посвящены различные статьи в интернете. Я не берусь рассуждать на эту тему, а лишь замечу, где Lisp мне пригодился. По большей части я использовал Lisp в качестве встраиваемого языка. Для управления приложениями через консоль, для создания гибких конфигурационных файлов, для хранения структурированных данных, для передачи данных по сети, для реализации самопального самодельного RPC. На мой взгляд, удобно, когда все перечисленные варианты имеют одинаковый синтаксис да еще могут быть расширены(в плане синтаксиса и функционала) причем на лету.

Я не считаю себя специалистом в мире Lisp и не гарантирую 100% точности изложенного материала. Одна из целей данной серии статей собрать разрозненную информацию относительно разных реализаций Scheme в одном месте и на родном языке. В общем, данный материал не для тех, кто хочет знать зачем, а для тех, кто хочет знать как. Если кому-то тема будет интересна и полезна, пишите, будем уточнять что есть и думать над продолжением.

Начало


Почти каждая статья о Lisp начинается с того, что Lisp один из самых старых языков программирования высокого уровня и общего назначения, который где-то в 1958г был изобретен Джоном Маккарти. Несмотря на древность Lisp мультипарадигмальный язык, позволяющий писать в функциональном, процедурном, объектно-ориентированном стилях. При этом, вся эта мультипарадигмальность доступна через примитивный и единообразный синтаксис, так называемые S-выражения. Для описания Lisp синтаксиса в форме Бэкуса—Наура достаточно всего 7 строк, с оговорками конечно. Так сложилось, что за долгую историю развития над Lisp ломали голову лучшие умы компьютерных наук, шлифуя его словно драгоценный камень. Однако нельзя сказать, что Lisp очень популярен, возможно, тому виной пугающее нагромождение скобок, из-за которого на первый взгляд программа выглядит сложной для восприятия. Но после небольшой практики дискомфорт переходит в восторг от тех возможностей, которые предоставляет данный способ программирования. По крайней мере, так было у меня).

Если быть чуть более точным, Lisp это не то чтобы язык программирования, сколько идея, на базе которой разработаны языки Lisp-семейства. В наши дни существует великое множество Lisp диалектов, а их реализаций еще больше. Что не удивительно, ведь написать интерпретатор лиспа относительно не сложно. Так повернулось колесо истории, что наиболее популярными диалектами стали Common lisp, Scheme и Clojure. Каждый диалект преследует свои, чуть отличные цели. Common Lisp – довольно пожилой промышленный стандарт, имеет в своем арсенале не малое количество библиотек и наработок. Scheme – стремится к минимальности базовых конструкций, через которые может быть выражена вся остальная функциональность, многообразие стилей и подходов программирования. То есть минималистичный интерпретатор и развитая стандартная библиотека. Clojure – свежий взгляд на Lisp в целом, были переосмыслены многие конструкции языка для удобной разработки поверх платформы JAVA в первую очередь. Как пишут на форумах разрабатывать под Clujure куда продуктивнее и интереснее чем на JAVA. Исключительно в целях самообучения я попробовал на вкус разные диалекты и их реализации. Можно бесконечно долго спорить Scheme vs Common Lisp, но для себя я выбор сделал в пользу Scheme за лаконичность, современность и доступность реализаций на различных платформах.

Про Scheme на форумах можно встретить отзывы, будто это исключительно академический язык, который если и можно использовать на практике, то крайне неудобно из-за чрезмерного минимализма. Что-то подсказывало мне, то это не так. И вот, мой дорогой читатель, скажу тебе, что scheme, довольно гибкий язык программирования, при этом не перегружен хитрыми конструкциями и с успехом может конкурировать со многими популярными инструментами. А использовать его в качестве встраиваемого языка одно удовольствие. Относительная простота стандарта Scheme играет на руку, способствуя появлению множества реализаций. Фактически можно выбрать реализацию под любые нужды и разрабатывать полноценные приложения GUI, DB, WEB, используя Scheme в качестве основного языка.

Есть из чего выбрать


Любопытно, но часто наиболее популярные продукты практически не предоставляют выбора, вот тебе версия единственная и неповторимая, а все остальное либо устарело, либо чья-то самоделка.

Scheme, возможно благодаря простоте стандарта имеет довольно много реализаций, либо интерпретаторов, либо компиляторов, либо и то и другое сразу. Причем, имеются компиляторы в другие языки, что в некоторых случаях может оказаться крайне полезно.

В сети можно найти список известных реализаций, например на community.schemewiki.org опубликована таблица.

Известные реализации Scheme

А если хорошенько поискать на GitHub, то становится ясно что вариантов еще больше.

Следование стандарту в различных реализациях позволяет повторно использовать код на разных платформах, в том числе и для Web программирования. Но не нужно забывать, что функционал не входящий в стандарт с высокой вероятностью будет отличаться, что приведет к непортируемости кода.

В металле


Чаще в своей практике я сталкиваюсь с программированием для .NET. Следовательно, для меня наиболее полезно решение позволяющее использовать .NET библиотеки и встраивать интерпретатор Scheme в свои приложения. Поиграв с разными вариантами, я остановился на IronScheme. Так, как он, на первый взгляд показался наиболее продвинутой реализацией стандарта R6Rs для .NET. Но есть и другие, о которых будет написано в следующих статьях.

IronScheme реализует шестую версию стандарта R6Rs. Естественно, имеет встроенный функционал для взаимодействия со средой исполнения clr. Таким образом, прямо из скрипта Scheme можем создавать и манипулировать .NET классами. А этого уже вполне достаточно чтобы создать полноценное приложение с GUI, DB и прочими вкусностями, которые доступны из .NET. Но мы не обязаны писать на IronScheme полноценные программы. Тем более что в поставляемых библиотеках имеются обертки для небольшого числа стандартных .NET классов. Хотя ни кто не мешает нам помочь сообществу.

Настройка среды


  1. Чтобы начать использовать IronScheme качаем архив с ironscheme.codeplex.com/;
  2. распаковываем например в “Program Files (x86)”;
  3. добавляем в переменную среды PATH «C:\Program Files (x86)\IronScheme\» ;
  4. для удобства в директории с IronScheme я создаю фай «is.bat» с содержимым «IronScheme.Console-v4.exe %1»;
  5. Выполнив команду IronScheme.Console-v4.exe запустим интерпретатор в REPL режиме.


Теперь можно вводить команды, например «(+ 2 2)». Интерпретатор в REPL режиме поддерживает автодополнение по нажатию на TAB, что удобно использовать в качестве справочника команд или для проверки фрагментов кода. Для выхода из интерпретатора нужно набрать «(exit)».

Здравствуй мир!


По сложившейся традиции напишем и запустим Hello world приложение. В любом привычном текстовом редакторе, желательно поддерживающим Scheme, например Sublime, создадим файл и сохраним его hello-world.ss.

Содержимое файла hello-world.ss:

(import 
  (rnrs) 
  (ironscheme)
)

(displayln "Hello, world!")


Запускаем командой «IronScheme.Console-v4.exe hello-world.ss» в результате получим долгожданную надпись.

© Habrahabr.ru