]]> ]]>

Scheme

Диалект языка программирования Lisp

Scheme — один из двух самых популярных диалектов Lisp. Scheme придерживается философии минимализма и предоставляет программисту небольшой базовый язык и мощный инструментарий для его расширения.

Scheme был разработан Гаем Стилом (Guy L. Steele) и Джеральдом Сассменом (Gerald Jay Sussman) в 1975 году и представлен в серии статей, так называемых Lambda Papers, в последующие пять лет. Диалект стандартизован IEEE Standard for the Scheme Programming Language 1995 года, а также серией фактических стандартов Revised n Report on the Algorithmic Language Scheme (RnRS):

  • Scheme, 1975 : Sussman, Steele
  • R1RS, 1978 : Steele, Sussman
  • R2RS, 1985: Clinger
  • R3RS, 1986: Clinger, Rees
  • R4RS, 1991: Clinger, Rees
  • R5RS, 1998: Kelsey и к.
  • R6RS, 2007: Sperber и к.
  • R7RS, 201x: в 2009 году Scheme Steering Committee, следящий за процессом стандартизации, объявил о намерении разбить диалект на два, Small и Large, первый из которых будет следовать традициям минимализма, а второй, строгое надмножество первого, будет развитым современным языком.

Основные особенности Scheme (отличия от других диалектов Lisp):

  • минимализм языка, основанный на лямбда-исчислении, которое используется для получения значительной части синтаксиса языка (11 из 23 синтаксических конструкций) из более примитивных конструкций.
  • статическая лексическая область видимости: имя переменной относится к самой локальной области видимости; таким образом, код можно читать и интерпретировать вне зависимости от того, в каком контексте он будет вызываться.
  • блоки, выражающиеся тремя конструкциями let, let* и letrec.
  • “правильная” хвостовая рекурсия, позволяющая записывать итеративные алгоритмы более идиоматично, через рекурсию, и при этом оптимизирующая их так, чтобы поддерживать неограниченное количество активных вызовов.
  • продолжения (абстрактные представления состояний программы) как объекты первого класса (процедура call-with-current-continuation).
  • общее пространство имен для переменных и процедур.

Scheme logo
Scheme logo

Примеры:

Hello, World!:

Пример для версий JScheme 7.2, MIT/GNU Scheme 7.7.9, guile 1.8.5

Вывод строки на печать — побочный эффект выполнения этой команды. В зависимости от выбранной реализации, команда вернет либо выведенный текст, либо Unspecified return value.

(write "Hello, World!")

Факториал:

Пример для версий JScheme 7.2, MIT/GNU Scheme 7.7.9, guile 1.8.5

Используется рекурсивное определение факториала. Отметим, что GNU Guile и MIT/GNU Scheme выводит правильный результат, а в JScheme возникает переполнение, и факториалы с 13! вычисляются неправильно.

(define (factorial x)
  (if (< x 2)
    1
    (* x (factorial (- x 1)))))

(do ((i 0 (+ i 1)))
  ((> i 16))
    (display (string-append (number->string i) "! = "))
    (display (number->string (factorial i)))
    (newline))

Числа Фибоначчи:

Пример для версий JScheme 7.2, MIT/GNU Scheme 7.7.9, guile 1.8.5

Используется рекурсивное определение чисел Фибоначчи.

(define (fibonacci x)
  (if (< x 2)
    x
    (+ (fibonacci (- x 1)) (fibonacci (- x 2)))))

(do ((i 1 (+ i 1)))
  ((> i 16))
    (display (string-append (number->string (fibonacci i)) ", ")))
(display "...")
(newline)

Квадратное уравнение:

Пример для версий guile 1.8.5

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

(define A (read))
(define B (read))
(define C (read))
(define D (- (* B B) (* 4 A C)))
(if (= A 0)
  (display "Not a quadratic equation.")
  (begin
   (define k1 (/ B -2 A))
   (define k2 (/ (sqrt (abs D)) 2 A))
   (if (= D 0)
    (begin (display "x = ") (display k1))
    (if (> D 0)
      (begin (display "x1 = ") (display (+ k1 k2)) (newline) (display "x2 = ") (display (- k1 k2)))
      (begin (display "x1 = (") (display k1) (display ", ") (display k2) (display ")") (newline)
             (display "x2 = (") (display k1) (display ", ") (display (- k2)) (display ")"))))))

CamelCase:

Пример для версий guile 1.8.5

В этом примере показана работа с регулярными выражениями из модуля regex. Первые две строки подключают нужные модули. Третья — читает строку из входных данных командой read-line (модуль rdelim) — в отличие от read, она читает все символы до конца строки, а не до первого пробела — и переводит ее в нижний регистр.

Четвертая команда находит все последовательности букв нижнего регистра в строке. Для каждой такой последовательности она заменяет ее на результат применения к ней некоторой функции (привязанной с помощью lambda). В данном случае это функция string-titlecase, переводящая первый символ строки в верхний регистр.

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

(use-modules (ice-9 regex))
(use-modules (ice-9 rdelim))
(define text (string-downcase (read-line)))
(define text (regexp-substitute/global #f "[a-z]+"  text 'pre (lambda (m) (string-titlecase (match:substring m))) 'post))
(define text (regexp-substitute/global #f "[^a-zA-Z]+"  text 'pre 'post))
(display text)

Комментарии

]]>

blog comments powered by Disqus

]]>

Работа программистам