Сайт о телевидении

Сайт о телевидении

» » Scheme (язык программирования). Поддержка языка Scheme

Scheme (язык программирования). Поддержка языка Scheme

У каждого языка программирования своё назначение. Одни прекрасно подходят для веба, другие для десктопных приложений, в третьих нуждается Data Science, а есть языки, которые идеально подходят для знакомства с программированием. Мы уже говорили про Logo, про Scratch, пришло время перейти на более высокую ступень образования и познакомить вас с Scheme.

Краткая справка

В конце 60-х годов 20 века ученые Массачусетского технологического института Гай Стил (Guy Steele) и Джеральд Сассмен (Gerald Sussman) приступили к разработке очередного диалекта языка Lisp. Они хотели лишь его ограничений, в том числе сложности синтаксиса и не до конца проработанных алгоритмов функционального программирования.

В итоге ученые опубликовали целую серию заметок, выходивших вплоть до 1980 года, в которых описывались идеи лямбда-вычислений, хвостовой рекурсии и итеративного подхода. Позднее они получили название Lambda Papers и стали одним из катализаторов запуска функционального программирования в массы.

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

Синтаксис

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

    Круглые скобки. Любое законченное выражение должно быть заключено в них. Это отпугивает тех, кто видит код впервые, но впоследствии на практике не вызывает сложностей.

    Никаких дополнительных служебных символов. Хватит скобок. Точка с запятой, кстати, отделяет от кода комментарии.

    Построение конструкций по типу «действие-предмет». В языке программирования это смотрится необычно, но в переводе на естественный язык вполне понятно.

В остальном, с точки зрения синтаксиса - классический упрощённый язык программирования. Взгляните на простой пример вычисления факториала:

(define (factorial n)
(if (= n 0)
1
(* n (factorial (- n 1)))))

Как видите, кроме порядка записи и большого количества скобок, ничего необычного.

Где применяется

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

А вот в жизни после учебы Scheme не имеет конкретной области применения. Как правило это продолжения студенческих проектов, небольшие куски кода и пробные релизы. Причин непопулярности несколько:

  • большой объём кода;
  • сложность отладки и поиска ошибок;
  • отсутствие функциональных преимуществ в сравнении с Common Lisp, Haskell, Clojure и пр.

В общем, зарабатывать деньги языком Scheme весьма проблематично.

Однако для желающих применить знания на практике были разработаны интерпретаторы: Racket и Bigloo . Они расширяют стандартные возможности Scheme, в том числе синтаксис, а также открывают новый функционал: визуализация, работа с матрицами и массивами, прямое взаимодействие с другими языками.

Перспективы

Несмотря на то, что Scheme нашёл себя только в образовании, он входит в топ-50 рейтинга TIOBE . Но есть негативная тенденция - язык ежегодно теряет 0,05% популярности. Вызвано это появлением конкурентов, пригодных для функционального программирования, имеющих больше возможностей для применения в жизни, и при этом простых.

Таким образом, велика вероятность, что через 5-10 лет язык пропадёт с радаров, а его место займёт какой-нибудь Scratch. Но пока этого не произошло, давайте уделим несколько минут своей жизни знакомству с Scheme. Своей 47-летней историей он это заслужил.

Кен Дики (перевод Алексея Десятника)

Альтернативный взгляд на мир

Каждый язык программирования представляет собой определенное мировоззрение в понятиях, которые он позволяет (или не позволяет) использовать. Эта серия статей описывает взгляд на мир языка программирования Схема («Схематичное мировоззрение»). Данное мировоззрение содержит множество современных элементов программирования: поддержка различных парадигм программирования, легко сочетаемые, многократно используемые абстракции, возможность создания языка, «заточенного» под определенное применение, четкое различие между переносимыми и непереносимыми частями программы, масштабируемость, начиная от отдельных утилит и заканчивая серьезнейшими программными системами.

Схема начиналась как эксперимент в разработке языка программирования для тестирования некоторых фундаментальных положений в теории разработки программ. Сейчас же она получает расположение со стороны многих известных университетов (таких, как МТИ – Массачусетский Технический Институт) в качестве первого изучаемого языка программирования. Кроме того, Схема используется в промышленности такими компаниями, как DEC , Texas Instruments , Tektronix , Hewlett Packard и Sun .

Что такое Схема?

Схема – это маленький, исключительно «чистый» язык, который (что очень важно!) приятно использовать. Схема разрабатывалась таким образом, чтобы малое число универсальных конструкций можно было легко использовать в разных стилях программирования: функциональном, объектно-ориентированном и императивном. Стандарт языка занимает всего около 50 (!) страниц, включая формальное определение семантики. Схема основывается на формальной модели лямбда-вычислений, так что здесь полно особенностей, удобных для теоретиков; это позволяет достаточно легко построить умные средства разработки программ.

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

На что же похожа Схема? Ну, она сильно смахивает на Лисп. Пусть это вас не пугает: внешний вид Схемы можно изменить (и этим мы займемся в будущем). Что действительно важно, так это те концепции, которые положены в основу Схемы, и возможности их использовать. Итак, давайте сравним Схему и какой-нибудь «классический» язык программирования – скажем, Си. Возможно, вы уже знаете, что Схема использует префиксную запись, в отличие от инфиксной записи Си:

Схема

Си

(+ 2 3 4)

(2 + 3 + 4)

(< low x high)

((low < x) && (x < high))

(+ (* 2 3) (* 4 5))

((2 * 3) + (4 * 5))

(f x y)

f(x, y)

(define (square x) (* x x))

int square(int x)

return (x * x)

В Схеме все типы данных эквивалентны. Все, что можно сделать с одним типом данных, можно сделать со всеми остальными. Это резко отличается от большинства языков программирования, в которых есть специальные операции для некоторых типов данных, а применение некоторых других типов данных специально ограничено. В большинстве языков, например, числа имеют особые права: они могут быть использованы без присваивания им имен (вообразите, что, например, что в Бейсике каждому число надо было бы назначать имя перед его использованием!). Функции, наоборот, ограничены: они обязаны иметь имя.

В Схеме, функции без имени создаются с помощью ключевого слова lambda :

(lambd a (x) (* x x)); результат – функция!

(define sq (lambda (x) (* x x))

(sq 9) ; 27

((lambda (x) (* x x)) 9) ; 27

((if (foo? x) * +) 2 3 4) ; если (foo? x) истинно ,

; то (* 2 3 4) ,

; иначе (+ 2 3 4)

(define (curried-add x) (lambda (y) (+ x y))

(define add3 (curried-add 3)) ; add3 - функция

(add3 7) ; 10

((curried-add 3) 7) ; 10

Основные моменты:

Переменная может содержать значение любого типа;

Имена обозначают значения; имена не обязательны;

Выражение – одна или несколько форм между скобками;

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

Комментарий начинается символом «точка с запятой» (;) и продолжается до конца строки;

Когда функция вычисляется, она «вспоминает» состояние «окружающей среды», в которой она создавалась (так что add 3 вспоминает, что X было равно трем в момент ее создания, т.е. в момент вычисления выражения ( lambda ( y ) (+ x y )) 7) ).

( define ( sq x ) (* x x )) – это всего лишь другая форма записи выражения

(define sq (lambda (x) (* x x))

Возможны семь видов выражений:

Константы: "foo#\Z3”строка”

Ссылки на переменные: foo joe a - long - name @#$!+-*/%<>

Создание функции: ( lambda ( z ) (* z z z ))

Применение процедуры: ( cube 37)

Условие: (if (< x 3) sqrt modulo)

Присваивание значения: ( set ! x 5)

Последовательность: ( begin ( write x ) ( write y ) ( newline ))

(разумеется, в этом списке перечислены далеко не все варианты выражений)

Схема имеет обычный набор типов данных:

Литеры (character): #\a #\A \#space #\newline

Строки (string ): ”строка текста”

Массивы (векторы – vector ): #(1 2 ”строка” #\ x 5)

Списки (list): (a little (list of) (lists))

Числа (numbers): 47 1/3 2.3 4.3e14 1+3i

Функции (function )

Логические значения (boolean , соотв. истина и ложь): # t # f

Порты (например, открытые файлы или сетевые соединения)

Символы (symbol , обычно используются для обозначения переменных): this - is - a - symbol foo a 32 > adfasf 23@#$%!<

Основные моменты:

Вектор может состоять из любых объектов данных;

Символ может содержать буквы английского алфавита, цифры и литеры + - . * / < = > ! ? : $ % _& ~ ^

Символы не чувствительны к регистру букв (т.е. символы SYMBOL и SyMboL идентичны)

Символы используются для обозначения переменных (но не только для этого!)

По соглашению (просто для удобства) предикаты (выражения проверки значений) заканчиваются на вопросительный знак, а «опасные» (изменяющие значение переменной) функции оканчиваются на восклицательный знак

Числа особенно интересны в Схеме: каждое целое (integer ) является дробью (rational ), дробь – действительным числом (real ), а действительное число – комплексным (complex ). Числа классифицируются по признаку точности (точное или приблизительное – exact /inexact ):

(exact? 3); #t

(exact? 1/3); #t

(exact? 2.3##); #f

(+ 2/3 1/2 5/6); 2

(integer? 2); #t

(integer? 3/7); #f

(real? 2); #t

Философия Схемы

Одна из приятных особенностей Схемы, которая поначалу многих приводит в замешательство – отсутствие ограничений. Схема очень выразительна: программист может «сказать» на этом языке одну мысль (действие) совершенно разными способами. В Схеме программист имеет свободу – и ответственность – «говорить» в точности так, как хочет. Во многих других языках программирования порой приходится искать какие-то «обходные пути», чтобы получить от них требуемое, а в Схеме это просто не нужно.

Для «разогрева» давайте построим структуру данных «пара» (pair ). Пара состоит из двух элементов, получаемых с помощью функций доступа FIRST и SECOND (соответственно ПЕРВЫЙ и ВТОРОЙ). Функция создания пары будет называться PAIR . Должны выполняться следующие соотношения: ( first ( pair 1 2)) равно 1, ( second ( pair 1 2)) равно 2. Для знающих Лисп в этом нет ничего необычного. Однако сколькими разными способами мы можем реализовать это трио: PAIR , FIRST , SECOND ?

; 1. Вектор

; можно и просто (define PAIR vector ) , но так стилистически лучше

(define (PAIR a b) (vector a b))

(define (FIRSTaPair) (vector-ref aPair 0))

(define (SECOND aPair) (vector-ref aPair 1))

; 2. Ф ункция выбора

; Не забывайте про лексическую область видимости:

; каждая функция, создаваемая функцией PAIR, будет помнить

; значения a и b в момент создания

(define (PAIR a b) (lambda (bool) (if bool a b)))

(define (FIRSTaPair) (aPair #t))

(define (SECOND aPair) (aPair #f))

; 3. Передача сообщений

(define (PAIR (a b)

(lambda (msg)

(case msg ; конструкция case для каждого значения msg

; выполняет соответствующее действие

((first ) a ) ; если сообщение – символ first ,

; возвратить a

((second) b))))

; апостроф (‘) перед символом запрещает вычислять его значение

; (без него была бы ошибка «отсутствует переменная»)

(define (FIRSTaPair) (aPair ‘first))

(define (SECOND aPair) (aPair ‘second))

; 4. Псевдонимы: в Схеме уже есть тип данных «пара»!

(define PAIRcons)

(define FIRSTcar)

(define SECOND cdr)

; 5. Лямбда-функции (передача функций как параметров другим

; функциям )

(define (PAIR a b) (lambda (proc) (proc a b)))

(define (FIRSTaPair) (aPair (lambda (x y) x)))

(define (SECOND aPair) (aPair (lambda (x y) y)))

Смысл всего вышеприведенного: даже простейшие вещи можно сделать совершенно по-разному.

Теперь, когда мы разогрелись, давайте взглянем на старый добрый факториал (напоминаю: факториал – произведение всех целых чисел от 1 до данного числа).

Для начала – рекурсивное определение:

(define (fact n)

(if (< n 2)

(* n (fact (- n 1)))

Когда я (Кен Дики) впервые изучал рекурсивные определения наподобие этого, самым сложным было понять, как скрытое состояние функции хранится на стеке. Небольшое преобразование кода делает стек видимым.

; функция identity просто возвращает свой аргумент

(define (identity value) value)

; сохраним форму функции fact

; (теперь она всего лишь вызывает функцию cfact )

(define (fact n) (cfact n identity))

; А функция cfact – вычисляет факториал

(define (cfact n k)

(if (< n 2)

(k 1)

(cfact (- n 1)

(lambda (result) (k (* n result))))))

Функция cfact – версия функции fact , использующая «продолжения». Вместо возвращения результата каждый раз функция получает дополнительный аргумент, «продолжение», который и вызывается с результатом вычислений функции.

Давайте посмотрим, как будет преобразовываться вызов ( fact 3) :

(fact 3) становится (cfact 3 identity)

(cfact 3 identity) становится

(cfact 2

(lambda (result)

(identity (* 3 result)))) ; k’

Это в свою очередь преобразовывается в

(cfact 1

(lambda (result’) ;; k’’

((lambda (result)

(identity (* 3 result))) ; функция k"

(* 2 result ’)) ; аргумент, передаваемый k "

((lambda (result’) ;; k’’

((lambda (result)

(identity (* 3 result)))(* 2 result’))

) 1)

((lambda (result) (identity (* 3 result))) (* 2 1))

(identity (* 3 (* 2 1)))

(* 3 (* 2 1))

-> 6

Это – не пример того, как из простых вещей можно легко сделать ужасно сложные. Зачем же мы так сделали? Смысл в том, что мы можем управлять тем, что обычно спрятано на стеке. Это позволяет делать некоторые интересные вещи. Мы можем игнорировать одно «продолжение» и использовать вместо него другое. Мы можем контролировать, например, длительные вычисления. Если они занимают больше времени, чем ожидалось, мы можем сохранить наше продолжение («где мы сейчас») и попробовать другой подход к решению задачи. Если новый вариант еще хуже, мы можем вернуться к сохраненному «продолжению» и продолжить вычисления. Мы, конечно, сможем сохранить и наши попытки сделать лучше на тот случай, если действительно получилось лучше…

Таким образом, использование «продолжений» позволяет строить очень интересные, гибкие управляющие структуры. Давайте теперь посмотрим на факториал с другой стороны. Каждый рекурсивный вызов просто кладет на стек еще один множитель. Но мы можем и не использовать стек, если введем дополнительную переменную-«аккумулятор». Разумеется, перед началом вычислений аккумулятор должен быть равен 1 (так как x *1 = x ).

(define (fact n)

; определяем функцию вычисления факториала с аккумулятором

(define (cfact _n acc)

(if (< _n 2)

(cfact (- _n 1) (* _n acc))

; вызываем эту функцию с аккумулятором, равным 1

(cfact n 1)

Внешне эта функция кажется рекурсивной. Однако это не так. В Схеме есть понятие «хвостовой рекурсии», которая делает ненужными обычные циклы. Каждая функция, которая вызывает саму себя в «хвостовой» позиции (т.е. как последнее действие) – это просто цикл.

Итак, мы преобразовали рекурсивную функцию в итеративную, циклическую. Есть формальный (теоретически «правильный») способ такого преобразования; но одна приятная особенность Схемы в том, что эти преобразования просты и наглядны. Правильно работающие программы могут быть написаны быстро, даже если поначалу они могут медленно работать и требовать много памяти. После отладки алгоритма их несложно преобразовать в намного более эффективные – и тоже правильно работающие! Преобразование программ для опытного программиста на Схеме становится второй натурой.

Схема имеет несколько важных преимуществ над другими языками. Ее элегантно простая, однородная структура и тривиальный синтаксис позволяет избегать разных «особых случаев». Ее выразительность позволяет не тратить время на поиск обходных путей: программист может сконцентрироваться на том, что ему нужно сделать, но не на том, как это сделать. Схема поддерживает несколько стилей программирования, включая модное сегодня объектно-ориентированное, – так что программист не должен приспосабливаться под Схему; он может использовать тот стиль или способ решения задач, к которому привык. Формальность Схемы делает доказательство правильности программ намного более простым. Мощные средства абстрагирования позволяют отделить части программы, которые можно повторно использовать, от частей, «заточенных» под конкретную проблему/реализацию языка/операционную систему. Легкость сочетания различных функций и создания на их основе новых конструкций позволяет создавать целые библиотеки хорошо отлаженных, универсальных компонентов.

Иначе говоря, если вы хотите писать сложные, корректные программы, но не хотите тратить на это годы, Схема – то, что нужно для успеха!

Краткий список наиболее известных реализаций Схемы.

Chez Scheme и MacScheme – одни из лучших коммерческих реализаций; однако существует множество бесплатных интерпретаторов и компиляторов Схемы как для учебных целей, так и для серьезной работы.

Одна из лучших систем для Windows и Linux – MzScheme , и построенные на ее основе MrEd (система создания переносимого графического интерфейса пользователя) и DrScheme (пожалуй, самая удобная среда разработки программ из существующих).

Введение

При разработке Scheme упор был сделан на элегантность и простоту языка. Философия языка подчёркнуто минималистская. Его цель - не сваливать в кучу разные полезные конструкции и средства, а напротив - удалить слабости и ограничения, вызывающие необходимость добавления в язык новых возможностей. В результате, Scheme содержит минимум примитивных конструкций и позволяет выразить все, что угодно путём надстройки над ними. В качестве примера можно указать, что язык использует 2 механизма организации циклов:

  1. «остаточная» или «хвостовая» рекурсия (англ. tail recursion )
  2. итеративный подход (в котором используются временные переменные для сохранения промежуточного результата).

Scheme был первым диалектом Лиспа , применяющим исключительно статические (а не динамические) области видимости переменных, гарантирующим оптимизацию хвостовой рекурсии и поддерживающим данные булевского типа (#t и #f вместо традиционно неуклюжих T и NIL). Он также был одним из первых языков, непосредственно поддерживающих продолжения (англ. continuations ). Начиная со спецификации R^5RS, язык приобрел исключительно мощное и удобное средство для записи макросов на основе шаблонов синтаксического преобразования с «соблюдением гигиены» (англ. hygienic_macro ). В Scheme также реализована «сборка мусора » (англ. garbage collection ), то есть автоматическое освобождение памяти от неиспользуемых более объектов.

В качестве базовых структур данных язык использует списки и одномерные массивы («векторы»). В соответствии с декларируемым минимализмом, (пока) нет стандартного синтаксиса для поддержки структур с именованными полями, а также средств ООП - все это может быть реализовано программистом по его предпочтению, хотя большинство реализаций языка предлагают готовые механизмы.

Как курьёз, можно отметить, что первоначальное название языка Schemer было изменено на настоящее из-за тогдашнего ограничения на длину имён файлов в ITS.

Примеры

Простые математические операции

(+ 2 (* 2 2 ) ) (+ 1 2 3 4 )

Вызов каждой операции (или функции) представляется списком, в котором символ операции (который, в сущности, является именем функции) всегда занимает начальную позицию.

Предикаты типа

(number? 5 ) (number? "foo" ) (string ? "foo" )

По соглашению, имена всех предикатов заканчиваются символом? .

Проверки на равенство

(eq? "foo" "bar" ) (eq? 5 (+ 2 3 ) ) (eq? (eq? 2 3 ) (eq? 3 4 ) )

Определение макросов для традиционных операций push/pop

(define-syntax push! (syntax-rules () ((push! x l ) (set! l (cons x l ) ) ) ) ) (define-syntax pop! (syntax-rules () ((pop! l ) (let ((x (car l ) ) ) (set! l (cdr l ) ) x) ) ) )

Определение функций

;; факториал в (неэффективном) рекурсивном стиле (define (fact x) (if (< x 3 ) x (* (fact (- x 1 ) ) x) ) ) ;; функция Фибоначчи - требует двойной рекурсии (define (fib n) (cond ((= n 0 ) 0 ) ((= n 1 ) 1 ) (else (+ (fib (- n 1 ) ) (fib (- n 2 ) ) ) ) ) ) ;; сумма элементов списка в характерном для Scheme стиле ;; (вспомогательная функция loop выражает цикл с помощью ;; хвостовой рекурсии и переменной-аккумулятора) (define (sum-list x) (let loop ((x x) (n 0 ) ) (if (null? x) n (loop (cdr x) (+ (car x) n) ) ) ) ) (fact 14 ) (fib 10 ) (sum "(6 6 6 100 ) ) (sum (map fib "(1 2 3 4 ) ) )

Определение функции должно соответствовать следующему прототипу:

(define имя_функции (lambda (список_аргументов) (реализация_функции) ) ) ,

хотя на практике чаще используют сокращённую форму:

(define (имя_функции аргументы) (реализация_функции) ) .

Ввод / Вывод

(write (+ (read ) (read ) ) )

Ссылки

Русскоязычные ссылки

Англоязычные ссылки

Учебники на английском

  • Видео-лекции «Structure and Interpretation of Computer Programs» , Harold Abelson и Gerald Jay Sussman
  • The Scheme Programming Language , R. Kent Dybvig

Wikimedia Foundation . 2010 .

Смотреть что такое "Scheme (язык программирования)" в других словарях:

    Язык программирования формальная знаковая система, предназначенная для записи компьютерных программ. Язык программирования определяет набор лексических, синтаксических и семантических правил, задающих внешний вид программы и действия,… … Википедия

Язык Scheme традиционно имеет достаточно хорошую поддержку Emacs. Эта поддержка реализуется набором пакетов, которые могут работать как с произвольными реализациями этого языка (scheme-mode , cmuscheme , quack ), так и поддерживать только конкретные реализации (xscheme , gds , bee-mode , gambit ). Как правило, поддержка конкретных реализация имеет несколько больше возможностей по сравнению с пакетами, ориентированными на поддержку всех реализаций.

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

Scheme-mode

Scheme-mode поставляемый в поставке дистрибутивов Emacs является модификацией lisp-mode для работы с исходным кодом на языке Scheme. Данный пакет реализует следующую функциональность:

  • подсветку синтаксиса
  • расстановку отступов
  • подсветку парных скобок

На базе scheme-mode создано несколько других пакетов — , и другие, которые расширяют его функциональность добавлением функций для выполнения кода прямо из буфера Emacs, и т.п. вещей.

Данный режим включается автоматически для файлов, использующих стандартные расширения для файлов с исходными текстами на Scheme — .scm , .ss и т.п. Чтобы включить данный режим для других файлов, добавьте в свой файл инициализации следующий код (заменив.scm на нужное расширение):

(add-to-list "auto-mode-alist "("\\.scm$" . scheme-mode))

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

Cmuscheme

Пакет cmuscheme был написан Olin Shivers много лет назад, но до сих пор является одним из основных пакетов, обеспечивающих работу со Scheme. Данный пакет реализует интерактивную работу с интерпретаторами языка Scheme. Взаимодействие с интерпретатором реализуется за счет использовании возможностей пакета comint , входящего в поставку Emacs.

Настройка пакета

Настройка пакета достаточно проста — поместите в свой файл инициализации следующий код

(autoload "run-scheme "cmuscheme" "Run an inferior Scheme" t) (setq scheme-program-name "mzscheme" )

и пакет будет автоматически загружен при первом запуске функции run-scheme . Вторая строка в этом примере используется для указания имени интерпретатора Scheme, которое вы можете заменить на свой любимый диалект. Все настройки данного пакета также доступны для интерактивной настройки через группу настройки cmuscheme .

В буфере интерпретатора, создаваемом пакетом, используется специальный режим — inferior-scheme-mode , который можно настроить используя хук inferior-scheme-mode-hook . Кроме того, если существует файл ~/.emacs_SCHEMENAME или ~/.emacs.d/init_SCHEMENAME.scm (где SCHEMENAME — название интерпретатора), то они будут выполнены сразу после загрузки интерпретатора.

Работа с пакетом

Основной функцией пакета является функция run-scheme , которая запускает выбранный интерпретатор языка Scheme и позволяет производить интерактивное выполнение кода не покидая Emacs.

При этом вы можете управлять тем, какая часть кода (выделенный блок, определение функции или отдельное выражение) будет выполнена путем использования разных функций, определенных пакетом — функция scheme-send-definition (сочетания клавиш C-c C-e или C-M-x) передает для выполнения интерпретатору текущее определение; функция scheme-send-region (C-c C-r) позволяет выполнить выделенный кусок исходного кода; функция scheme-send-last-sexp (C-x C-e) используется для вычисления выражения, которое находится перед курсором; а функция scheme-load-file (C-c C-l) позволяет загрузить в интерпретатор файл целиком (она позволяет выполнить код из любого файла, указанного пользователем, а не только из текущего буфера).

Интерпретатор Scheme выполняется в отдельном буфере с именем *scheme* , куда также выводятся и результаты вычисления выражений и функций. Для быстрого переключения в этот буфер из буфера с исходным текстом, существует отдельная функция switch-to-scheme (C-c C-z). Кроме того, поскольку часто требуется выполнить код и просмотреть результаты, то в пакете также определены две функции, которые отправляют интерпретатору код для выполнения, и переключаются в буфер *scheme* — scheme-send-definition-and-go (C-c M-e) для вычисления текущего определения и scheme-send-region-and-go (C-c M-r) для вычисления выделенного исходного кода.

Для работы с макросами пакет предоставляет функцию scheme-expand-current-form (C-c C-x), которая позволяет раскрыть определение текущего макроса в соответствующий код на Scheme. Раскрытие кода производится интерпретатором и выводится в буфер *scheme* . А при работе с реализациями Scheme, которые поддерживают компиляцию исходного кода, пользователь может воспользоваться функциями scheme-compile-file (C-c C-k) и scheme-compile-definition (C-c M-c), которые соответственно выполняют компиляцию файла или текущего определения.

Как отмечалось выше, в буфере интерпретатора действует специальный режим — inferior-scheme-mode в котором работают все команды режима comint , а также следующие команды cmuscheme — scheme-compile-file (C-c C-k), scheme-load-file (C-c C-l), scheme-send-last-sexp (C-x C-e) и scheme-send-definition (C-M-x).

Quack

Пакет Quack является расширением для пакета cmuscheme и реализует следующие дополнительные возможности (многие из них в первую очередь относятся к работе с PLT Scheme):

  • меню, позволяющие получать доступ к документации по языку, интерпретатору и SRFI, а также возможность поиска описания для имени функции, находящегося в текущей позиции курсора;
  • новые наборы подсветки для font-lock — для PLT Scheme и расширенная, для других реализаций;
  • возможность использования греческого символа lambda для обозначения lambda-выражений (примеры приведены ниже);
  • дополнительные опции и команды для вставки правильных открывающих и закрывающих скобок;
  • расширения для правил расстановки отступов, с возможностью настройки для разных интерпретаторов Scheme;
  • расширенная версия команды run-scheme , которая знает имена команд популярных интерпретаторов Scheme, а также запоминает последний запущенный вариант интерпретатора;
  • расширенная версия команды switch-to-scheme ;
  • возможность просмотра содержимого.plt коллекций и команды для открытия буфера Dired для нужной коллекции.

Установка и настройка

Пакет написан Neil Van Dyke, и доступен для загрузки с сайта автора . Пакет устанавливается путем копирования в каталог, где Emacs сможет найти его, и загружается командой:

(require "quack )

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

Пользователям PLT Scheme рекомендуется скачать руководства по данному интерпретатору с сайта проекта и установить их в коллекцию doc . Нахождение коллекций PLT Scheme определяется либо переменной quack-pltcollect-dirs , в которой можно перечислить все каталоги с рабочими коллекциями, либо переменными среды PLTHOME и/или PLTCOLLECTS .

Также для работы пакета требуется наличие программы wget , которая будет использоваться для доступа к SRFI.

Работа с пакетом

После загрузки пакета, в дополнение к функциям cmuscheme и scheme-mode становятся доступными функции, определенные пакетом. Пользователь может выполнять эти функции либо используя стандартные механизмы (сочетания клавиш и/или запуск по имени функции), либо используя меню Quack .

Просмотр документации осуществляется с помощью нескольких функций. Функция quack-view-manual (C-c C-q m) используется для просмотра документации в веб-браузере. Эта команда позволяет просматривать как базовую документацию по языку Scheme, так и документацию по конкретным реализациям. Для просмотра SRFI определена отдельная команда — quack-view-srfi (C-c C-q s), которая запрашивает номер нужного документа и открывает его в браузере. А для пользователей PLT Scheme еще доступна и команда quack-view-keyword-docs (C-c C-q k), которая показывает документацию для заданного ключевого слова (работа этой команды зависит от правильной установки документации PLT Scheme ).

Как уже отмечалось выше, пакетом реализована функция run-scheme (C-c C-q r), которая позволяет запускать интерпретаторы языка Scheme, выбирая их из списка известных (включая запуск с нужными опциями), а также запоминает последний выбор пользователя.

Для пользователей PLT Scheme также определены удобные функции для работы с коллекциями. Функция quack-find-file (C-c C-q f) открывает файл, используя данные из текущего контекста для получения имени файла. Например, если вы используете эту функцию в то время как курсор находится на коде (require (lib "list.ss")) , то вам будет предложено открыть файл list.ss из коллекции mzlib . Кроме того, определена функция quack-dired-pltcollect , которая позволяет открыть буфер Dired для нужной коллекции PLT Scheme (при задании имени пользователь может использовать автодополнение имени коллекции).

Данный пакет также реализует несколько функций, которые изменяют форматирование кода, делая его более удобным для использования. Функция quack-tidy-buffer (C-c C-q t) заново расставляет отступы в коде, заменяет знаки табуляции на пробелы, удаляет лишние пустые строки, удаляет заключительные пробельные символы в строках, а также добавляет знак перевода строки в конце файла, если его нет. Функция quack-toggle-lambda (C-c C-q l) изменяет объявление текущей функции с (define (func args) ...) на (define func (lambda (args) ..)) , что позволяет показывать знак лямбда в коде (при включенной опции отображения данного символа). Например, вот так:

Пакет GCA

GCA — пакет предназначенный для эффективной работы с исходным кодом Scheme. Он разрабатывался для поддержки Gauche Scheme , но может использоваться и с другими диалектами. Как и quack , он расширяет функции пакета cmuscheme .

Данный пакет имеет следующие возможности:

  • вставку кусков кода, используя механизм шаблонов
  • показ описаний для функций
  • дополнение имен

Данный пакет имеет некоторые архитектурные отличия от других пакетов — вместо взаимодействия с интерпретаторами используя стандартный ввод и вывод, данный пакет использует простой сетевой протокол для передачи данных. Данный подход позволяет выполнять большее количество задач, но сильно зависит от реализации интерпретатора и требует отдельного процесса Scheme (сервера gds ), который будет использоваться взаимодействия с другими процессами.

Установка и настройка

Пакет gds поставляется вместе с последними версиями Guile, так что вам необходимо лишь добавить файлы с исходными текстами Emacs Lisp в пути поиска Emacs, и вписать в файл инициализации следующую строчку:

(require "gds )

Данная команда приводит к загрузке пакета и запуска отдельного процесса, который будет отвечать за взаимодействие с интерпретаторами Scheme. Стоит отметить, что для работы пакета необходимо наличие отдельного пакета на Scheme в путях поиска Guile. Если пакет находится в нестандартном месте, то вы можете указать его расположение с помощью переменной gds-scheme-directory , иначе, при отсутствии этого пакета, загрузка пакета не будет произведена полностью.

Остальные настройки могут быть заданы используя группу настройки gds .

Работа с исходным кодом

Пакет gds для вычисления кода использует те же сочетания клавиш, что и cmuscheme . Исключением является функция gds-eval-expression (C-c C-e), которая вычисляет выражение введенное в мини-буфере.

Одним из приятных добавлений, реализованных gds является дополнение имен функций и переменных, а также получение справки о конкретных символах и/или поиск символа по имени.

Дополнение имен производится функцией gds-complete-symbol (сочетание клавиш M-TAB), которая старается найти все известные символы, чьи имена соответствуют тем буквам, которые находятся перед курсором. Если найдено одно имя, то оно вставляется сразу, но если есть несколько вариантов, то будет показано новое окно, в котором пользователь может выбрать нужное имя.

Получение справки на конкретный символ производится с помощью функции gds-help-symbol (C-h g), которая выдает те же результаты, что и запуск команды (help SYMBOL) в интерактивной среде Guile. Имя символа запрашивается у пользователя через мини-буфер, но в качестве значения по умолчанию используется имя, на котором находится курсор. Если вы не помните точное имя символа, то вы можете воспользоваться функцией gds-apropos (C-h G), которая аналогична выполнению (apropos REGEXP) в Guile, и которая выводит список символов, чьи имена соответствуют введенному регулярному выражению.

Отладка

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

(use-modules (ice-9 gds-client debugging traps)) (named-module-use! "(guile-user) "(ice-9 session)) (gds-accept-input #f)

После этого, вы можете работать с gds . Для установки точки остановки в процедуре proc_name , используется следующий, вычисляемый в буфере с исходным кодом:

(install-trap (make #:behaviour gds-debug-trap #:procedure proc_name))

и после вызова указанной процедуры, в получите в буфере gds примерно следующее:

Calling procedure: => s s --:** PID XXXXX (Guile-Debug)--All--------

в этом буфере вы можете перемещаться по стеку, просматривать его состояние, продолжать выполнение программы, и/или пошаговое выполнение. Работа в буфере стека обеспечивается за счет использования некоторого количества команд, привязанных к отдельным клавишам.

Для перемещения по стеку вызовов функций могут использоваться следующие клавиши: u , C-p и стрелка вверх используются для перемещения вверх по стеку вызовов и выбора этого фрейма (функция gds-up), d , C-n и стрелка вниз — для перемещения вниз (gds-down), а клавиша RET используется для выбора фрейма на котором находится курсор.

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

К дополнительным функциям, работающим в буфере стека относятся следующие:

gds-evaluate (клавиша e) позволяет вычислить выражение, используя окружение, соответствующее выбранному фрейму, при этом результат отображается в эхо-области; gds-frame-info (i) показывает информацию о выбранном фрейме — строку в исходном файле, соответствующее выражение, тип фрейма и т.п.; gds-frame-args (A) показывает аргументы фрейма приложения; gds-proc-source (S) показывает исходный код вызванной процедуры. Эта функция очень полезна в тех случаях, когда процедура создана анонимным лямбда-выражением, поскольку такие процедуры показываются в стеке вызовов функций в виде Что не делает понятным, что будет выполнено дальше.

Для продолжения выполнения прерванной программы, gds реализует следующие функции:

gds-go (g , c или q) продолжает выполнение программы; gds-step-file (SPC) выполняет один шаг функций, относящихся к тому же исходному файлу, что и выбранный фрейм стека. Функции из других файлов будут выполняться, но без входа в них; gds-step-into (i) выполняет следующий шаг. Это наиболее детальный уровень выполнения программы; gds-step-over (o) выполняет программу до тех пор, пока не будет закончено выполнение выбранного фрейма стека.

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

Scheme48

scheme48 — еще один пакет основанный на cmuscheme , но реализующий расширенную поддержку реализации Scheme48. Данный пакет добавляет поддержку font-lock для ключевых слов и операторов, специфических для Scheme48, а также дополнительные привязки клавиш для команд вычисления выражений.

Процедура установки этого пакета стандартна — поместите gambit.el в место, где его найдет Emacs, и добавьте следующие строки в файл инициализации:

(autoload "gambit-inferior-mode "gambit" "Hook Gambit mode into cmuscheme." ) (autoload "gambit-mode "gambit" "Hook Gambit mode into scheme." ) (add-hook "inferior-scheme-mode-hook (function gambit-inferior-mode)) (add-hook "scheme-mode-hook (function gambit-mode)) (setq scheme-program-name "gsi -:d-" )

Интерпретатор Gambit запускается с помощью функции run-scheme , реализованной в cmuscheme , но gambit добавляет к ней процедуры фильтрации вывода, что позволяет пакету получать информацию о местоположении в исходном файле. После запуска интерпретатора, пользователь получает возможность использовать стандартные сочетания клавиш для выполнения и компиляции кода — C-x C-e , C-c C-l , C-c C-k и т.д.

В дополнение к функциям cmuscheme , пакет gambit предлагает несколько функций, предназначенных для отладки исходного кода:

gambit-continue (F8 или C-c c) продолжить выполнение кода. Аналогично команде,c интерпретатора; gambit-crawl-backtrace-newer (F9 или C-c ]) перейти к предыдущему фрейму в цепочке. Аналогично команде,- интерпретатора; gambit-crawl-backtrace-older (F10 или C-c [) перейти к следующему фрейму в цепочке. Аналогично команде,+ интерпретатора; gambit-step-continuation (F11 или C-c s) выполнить один шаг вычисления включая вхождение в вызываемую функцию. Аналогично команде,s интерпретатора; gambit-leap-continuation (F12 или C-c l) выполнить один шаг вычисления, не заходя в вызываемую функцию. Аналогично команде,l интерпретатора; gambit-kill-last-popup (C-c _) удалить окно, которое было создано для показа выражения.

Существуют и более короткие сочетания клавиш для этих команд: M-c , M-[ , M-] , M-s , M-l и M-_ , но они по умолчанию не активированы, поскольку они не совсем соответствуют соглашениям, принятым для сочетаний клавиш в Emacs. Чтобы разрешить их использование, вам необходимо выполнить следующую команду (или поместить ее в файл инициализации):

(setq gambit-repl-command-prefix "\e" )

Bee-mode (bmacs)

bmacs — это реализация интегрированной программной среды для работы с Bigloo Scheme . Данный пакет реализует следующие возможности:

  • отладку кода;
  • профилирование;
  • автоматическое создание и обновление файлов Makefile;
  • навигация по коду;
  • интеграция с системами контроля версий;
  • просмотр документации;
  • интерактивное выполнение кода;
  • раскрытие макросов;
  • некоторая поддержка грамотного стиля программирования (literate programming).

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

Установка и настройка

Данный пакет поставляется в составе Bigloo Scheme и находится в подкаталоге bmacs дистрибутива. Для установки пакета надо перейти в этот каталог и там выполнить команду:

Make make install EMACSDIR =

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

(autoload "bdb "bdb" "bdb mode" t) (autoload "bee-mode "bee-mode" "bee mode" t) (setq auto-mode-alist (append "(("\\.scm$" . bee-mode) ("\\.sch$" . bee-mode) ("\\.scme$" . bee-mode) ("\\.bgl$" . bee-mode) ("\\.bee$" . bee-mode)) auto-mode-alist))

Настройки пакета могут быть установлены используя группу настройки bee , которая обеспечивает задание настроек для bee-mode , и групп dbg & bug , используемых для задания настроек отладчика.

Работа с исходным кодом

После загрузки bee-mode пользователь может выполнять основные команды используя соответствующие иконки тулбара, или выбирая нужные пункты из меню Bee , которое появляется при запуске режима.

Для расстановки отступов в соответствии с принятыми для Bigloo соглашениями, пакет bee-mode определяет несколько функций: bee-indent-sexp (C-M-q) расставляет отступы для текущего выражения, bee-indent-define (C-c TAB C-d) делает это для текущего определения функции, bee-indent-last-sexp (C-c TAB C-l) расставляет отступы для выражения перед курсором и т.д.

Очень важный набор функций, используемых при работе с исходным кодом, это функции поиска определений функций и переменных. Чтобы найти определение переменной, вы можете воспользоваться функцией bee-tags-find (C-x 5 .) или bee-tags-find-variable (C-c C-d f). А для поиска определения модуля существует функция bee-find-module (C-c C-d m). Кроме того, bee-mode переопределяет два сочетания клавиш — M-. & M-, которые привязываются к функциям bee-tag-find и bee-tags-find-next , что позволяет находить определения функций и классов.

Для упрощения работы с модулями, bee-mode определяет набор функций, которые управляют списком модулей импортируемых текущим исходным кодом — функция bee-import-binding (C-c RET i), а также списком функций и переменных, экспортируемых из текущего модуля — bee-export-function (C-c RET f) и bee-export-variable (C-c RET v). Кроме того, существует отдельная функция, которая позволяет импортировать символы из файлов на языке C — bee-import-c-file (C-c RET c), а также она обновляет Makefile , добавляя зависимость для компиляции соответствующего кода.

Пакет также обеспечивает некоторую поддержку так называемого грамотного программирования (literate programming). Реализуемая поддержка не является полной, но по крайней мере позволяет вставлять в код ссылки на описания модулей и функций. Это достигается за счет использования ключевых слов @path , @node & @deffn в комментариях для модуля и описаний функций. Ключевые слова @path & @node определяют файл и раздел документации, описывающих данный модуль и указываются в комментарии для объявления модуля. А ключевое слово @deffn указывается в комментарии для функции. Используя эти ключевые слова, разработчик получает возможность быстрого перехода к соответствующим разделам и описаниям функций, что позволяет улучшить документирование кода.

Выполнение и компиляция кода

Также как и другие пакеты, bee-mode позволяет выполнять код Scheme непосредственно из буфера Emacs. Для запуска интерпретатора необходимо выполнить функцию ude-repl-other-frame (C-c C-r C-r), выбрать соответствующую иконку тулбара (Repl ), или соответствующий пункт меню.

И после загрузки интерпретатора, пользователь может выполнять код используя следующие функции:

  • ude-repl-send-buffer (C-c C-r b) передает для вычисления весь буфер;
  • ude-repl-send-region (C-c C-r r), передает интерпретатору выделенный блок кода;
  • bee-repl-send-define (C-c C-r d) используется для выполнения текущего определения (define);
  • bee-repl-send-last-sexp (C-c C-r l) вычисляет значение выражения перед курсором;
  • bee-repl-send-toplevel-sexp (C-c C-r t) используется для вычисления всего текущего выражения.

Очень часто при использовании макросов необходима возможность их раскрытия. Также как и для работы с обычным кодом, bee-mode реализует набор функций для раскрытия макросов в вашем коде (при этом, весь буфер будет просканирован на предмет наличия определений макросов):

  • bee-expand-buffer (C-c C-e C-e) приводит к раскрытию макросов в текущем буфере;
  • bee-expand-region (C-c C-e C-r) раскрывает макросы в выделенном коде;
  • bee-expand-define (C-c C-e C-d) раскрывает макросы в текущем определении (define)
  • bee-expand-last-sexp (C-c C-e C-l) производит раскрытие макросов в выражении перед курсором;
  • bee-expand-toplevel-sexp (C-c C-e C-t) раскрывает макросы в текущем выражении.

Для компиляции программ необходимо наличие файла Makefile , который описывает зависимости между модулями и указывает флаги компиляции. Для проекта необходимо наличие так называемого корневого каталога — bee-mode пытается определить корневой каталог проекта путем поиска одного из файлов Makefile , .afile или.etags , или корневой каталог может быть установлен с помощью функции ude-user-set-root-directory (C-c C-p C-r) или соответствующей кнопки тулбара.

После того, как корневой каталог задан, Makefile может быть сгенерирован с помощью функции ude-generate-makefile (C-c C-c a или C-c C-c C-l), которая запросит у пользователя имя исполняемого модуля, в который будет скомпилирован данный исходный код. В том случае, если Makefile уже существует, то эти же сочетания клавиш обновляют его, а также перестраивают файлы.afile и.etags . Кроме того, имеется набор функций для редактирования Makefile — ude-edit-makefile (C-c C-c e), обновления Makefile — ude-update-makefile (C-c C-c u), переключения между отладочной и окончательной версиями программы — ude-makefile-debug-mode (C-c C-c C-d) & ude-makefile-final-mode (C-c C-c C-f) и другие.

Когда Makefile существует, то появляется возможность компиляции кода с помощью функции ude-mode-compile-from-menu (C-c C-c C-c) . Прервать компиляцию можно с помощью функции kill-compilation (C-c C-c k).

И после того, как компиляция закончится, можно выполнить исполняемый модуль с помощью функции ude-execute (C-c C-c C-r).

Отладка и профилирование

Вместе с пакетом Bigloo поставляется и отладчик, который позволяет производить отладку на уровне исходного кода. bee-mode поддерживает взаимодействие с этим отладчиком в Emacs. Для запуска отладчика надо выполнить функцию bee-debug (C-c C-b C-b) или выбрать соответствующую иконку тулбара, или пункт меню. Но запуск отладчика не приводит к автоматическому подключению к нему, поэтому необходимо явно выполнить функцию bee-toggle-connect-buffer (C-c C-b c) чтобы связать текущий буфер с отладчиком, что позволит устанавливать точки останова и выполнять прочие задачи находясь в буфере с исходным текстом.

Профилирование программ поддерживается автоматически, если вы пользуетесь генерацией Makefile . Чтобы провести профилирование кода, необходимо его сначала скомпилировать с поддержкой профилирования, что выполняется функцией bee-profiler-start (C-c C-p c). А после компиляции, вы можете выполнить функцию bee-profiler-inspect (C-c C-p i), что приведет к запуску программы, и затем к запуску утилиты bglprof , которая соберет данные о выполнении, и вы получите их в удобном для анализа виде.

Прочие функции

Пакет предоставляет возможности по получению справочной информации. Это может быть сделано путем запуска функции bee-doc-visit (C-c C-d i) или нажатия на иконку Info в тулбаре. Эта функция ведет себя по разному в зависимости от текущего положения курсора — если курсор находится на идентификаторе, то выдается документация для данного идентификатора, если выделен регион кода, то будет выдана документация для данного региона. В противном случае, у пользователя будет запрошено имя интересующего раздела документации, и показан выбранный раздел.

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

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

Кроме того, существует множество дополнительных функций, реализованных данным пакетом, например, поддержка работы с кодом, написанным на языке C, и т.п., но описание этих возможностей лежит за границами данной статьи.

Поддержка Scheme в SLIME

Для использования SLIME со Scheme, вам необходимо выполнить базовую настройку пакета, как это описано в разделе посвященном этому пакету, а затем загрузить необходимые компоненты . В общем виде это делается следующим образом:

(add-hook "slime-load-hook (lambda () (require "slime-scheme )))

Эта команда установит хуки необходимые для работы со SLIME , но для каждого из поддерживамых диалектов вам может понадобиться выполнить дополнительную настройку в соответствии с инструкциями, изложенными в соответствующем файле — swank-kawa.scm или swank-mit-scheme.scm .

А все остальное, касающееся работы со SLIME , описано в соответствующем разделе .

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

Кроме того, в поставке bmacs также имеются пакеты cee , предназначенный для редактирования кода на языке C, используемого для написания расширений Bigloo, bug-mode, обеспечивающий поддержку отладчика Bigloo, и ude (Unix Development Environment), реализующий поддержку компиляции, и различных утилит, используемых в работе с Bigloo.

Стоит отметить, что если Makefile не существует, то эта функция приводит к запуску компиляции исполняемого модуля из одного файла.

Так называемый swank -модуль.

Все компоненты, относящиеся к Scheme, находятся в подкаталоге contrib дистрибутива SLIME, так что не забудьте добавить его в пути поиска.

Какой Язык выбрать для обучения программированию? Изучение программирования ни не стоит начинать где-то с середины.

Сначала нужно натренировать мозг, умение создавать алгоритмы и описывать их зная возможности того или иного языка. В отечественных школах и вузах обычно изучают программирование на примере Basic или Pascal. До сих пор Pascal считается одним из лучших языков для обучения, это строгая речь со статической типизацией, которая позволяет без лишних проблем отработать принципы процедурного и объектно-ориентированного программирования. Но, познакомившись с учебными материалами ведущих западных университетов (Berkeley, Stanford, MIT), схожусь во мнении, что неплохо было бы начать изучение с одного из функциональных языков.

Вообще, довольно странно, но функциональная парадигма упорно игнорируется отечественным образованием. Чтобы сгладить этот пробел, хотел бы рассказать о языке программирования Scheme.

Scheme - это очень простой язык программирования. Его вполне можно выучить за один день, но эта простота обманчива. Scheme одновременно и очень мощный язык. Существует огромное количество реализаций.

Программы сертификации сохраняются в * .scm файлах, или можно использовать интерактивный режим интерпретатора, по аналогии с Python.

Константы и переменные

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

123 - целое число

3.1415926 - дробное число

2 + 3i - комплексное число

2/3 - дробь

# B1111 - двоичное число

#xFF - шестнадцатеричное статья

# O123 - восьмеричное число

# \ A - единичный символ

"Hello, World!" - Символьная строка

"Hello - символ

#f - логич значение

С константами можно осуществлять операции с помощью операторов или функций. В конце концов Scheme является функциональным языком, а потому в нём есть все функции.

По математике вы знакомы с формой записи функций f (x) или t (a, b). Но то же самое можно записать и в виде (f x) или (t a b). Именно такую форму записи использует Scheme. Не как арифметическое выражение, которые записываются в форме, например 2 + 3, а в префиксальном - (+ 2 3).

К примеру:

guile> (+ (* 3 4) (/ 5 2))

29/2

guile> (+ 1 1 1 1 1)

guile> (/ 2)

guile> (sqrt 2)

1.4142135623731

Для объявления переменных используется конструкция (define имя значения)

guile> (define a 2)

guile> (define b 2)

guile> (+ a b)

Значение уже существующей переменной можно изменить с помощью конструкции (set! Имя значение)

guile> (set! a 5)

guile> a

Функции объявляются с помощью конструкции (define (имя параметра) тило_функции)

guile> (define (square x) (* x x))

guile> (square 3)

Для демонстрации рекурсии приведу пример вычисления факториала:

(Define (fact x)

(If (= x 1)

(* X (fact (- x 1)))))

Как вы уже поняли, проверку условия можно выполнять с помощью конструкции (if условие якщо_так якщо_ни)

Не углубляясь в подробности, обращу внимание на основные функции

(Display "Hello, World!") - Вывести строку

(Newline) - перейти на новую строку

Для работы с наборами данных удобно использовать списки

guile> (define nums (list 1 2 3 4 5 6 7 8 9 10)) - объявляем список

guile> (list-ref nums 0) - читаем элемент с номером 0

guile> (car nums) - читаем первый элемент

guile> (cdr nums) - читаем все остальные элементы

(2 3 4 5 6 7 8 9 10)

Можно обработать все элементы списка заодно

сгенерировать новый список применив функцию для каждого элемента

guile> (map square nums)

(1 4 9 16 25 36 49 64 81 100)

guile> (map (lambda (x) (* x 3)) nums)

(3 6 9 12 15 18 21 24 27 30)

Конструкция lambda позволяет объявлять функции по мере необходимости, не давая им имен. Если вы программируете на Python, то уже знаете эти конструкции.

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

(Define (print-list lst)

(If (not (null? Lst))

(Begin (display (car lst))

(Newline)

(Print-list (cdr lst)))))

Конструкция (begin ...) используется в том случае, если нужно вставить несколько операторов там где по синтаксису допускается только один.

Следующая конструкция позволяет смоделировать известный по другим языкам программирования цикл for:

(Let loop ((i 1))

(Display i)

(Newline)

(If (<= i 10) (loop (+ i 1))))

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

Например, можно привести реализацию функции вычисления определенного интеграла

(Define (func x)

(Define (integrate a b e f)

(Define sum 0)

(Let loop ((i a))

(If (

(Set! Sum (+ sum (* (f i) e)))

(Loop (+ i e)))))

Sum)

(Display (integrate 0 1 0.01 func))

(Newline)

Официальный сайт Guile

Schemers.org

Видеозаписи лекций по курсу The Structure and Interpretation of Computer Programs в университете Berkeley

Вообще, поскольку Scheme - язык академический, то информации по ней достаточно много. В то же время, знания данного языка позволит не только по-новому взглянуть на различные конструкции в других языках (как Python например).