Строки можно образовывать из повторений одиночных символов:
(make-string 5 #\z) => "zzzzz"
Легко вычисляется длина строки:
(string-length "Hello world!") => 12
Подстроки можно выделить из исходной строки:
> (substring "Apple" 1 3)
"pp"
> (substring "Apple" 1)
"pple"
Особое место в наборе процедур, манипулирующих строками, занимают преобразователи:
§ string->list - преобразование строки в список символов
§ list->string - преобразование из списка в строку
§ number->string - преобразование из числа в строку
§ string->number - преобразование из строки в число
(string->list "abc") => (#\a #\b #\c)
(list->string '(#\a #\b #\c)) => "abc"
(string->number "234") => 234
Пары
Точечная пара образуется путём слияния двух значений:
(cons 1 2) => (1 . 2)
(cons #t 1) => (#t . 1)
Для доступа к первому элементу используется конструкция car, а для доступа ко второму -cdr
(define ages (cons 20 25))
>ages
(20 . 25)
>(car ages)
>(cdr ages)
Для изменения объектов в паре используются операции set-car! и set-cdr!:
(set-car! ages 30)
(set-cdr! ages 35)
>ages
(30 . 35)
Пары могут вкладываться друг в друга:
(define ages (cons 20 25))
(define newages (cons ages 30))
>newages
((20 . 25) . 30)
Списки
Списки в Лиспе являются базовой структурой данных. Список - это произвольный набор значений, доступ к которым осуществляется последовательно, то есть медленней, чем к элементам вектора.
Создание списка:
>(list 0 1 2 3)
(0 1 2 3)
>'(5 6 7)
(5 6 7)
Списки могут содержать любые объекты, включая списки
Для доступа к первому элементу используется car, а cdr возвращает список из оставшихся элементов
Над списками предусмотрены многочисленные операции, среди которых
§ length - вычисление длины списка
§ reverse - перестановка элементов в обратном порядке
§ sort - сортировка списка по возрастанию
§ append - добавление элемента к списку
§ list-ref - обращение к элементу по номеру (с 0)
Определим именованный список:
>(define expres '(* 2 2))
>express
(* 2 2)
Поскольку expres содержит комбинацию, то её можно выполнить:
>(eval express)
20) Специальные формы
Выражения, начинающиеся со следующих ключевых слов, комбинациями не являются:
and, begin, case, cond, define,
do, if, lambda, let, let*, letrec,
or, quasiquote, quote, set!
Говорят, что они определяют специальные формы, которые имеют свой порядок вычисления.
Условные выражения
Несколько специальных форм касаются вычислений условных выражений:
(if (> 3 2) 'yes 'no) => yes
(if (> 2 3) 'yes 'no) => no
(if (> 3 2)
(- 3 2)
(+ 3 2)) => 1
В приведённых примерах, в зависимости от результата контрольного выражения ((> 3 2) и др.) выдаётся результат всего выражения. Перед словами yes, no расположен апостроф, который заставляет интерпретатор воспринимать слово как данные, а не как имя процедуры или переменной.
Специальная форма if работает с количеством альтернатив не более двух, а более общий случай связан с использованием формы cond:
(cond ((> 3 3) 'greater)
((< 3 3) 'less)
(else 'equal)) => equal
Блок else выполняется в случае, если контрольные выражения для каждой строки имеют значение #f.
Специальная форма case сопоставляет с результатом контрольного выражения несколько выражений, каждое из которых включает список объектов и выдаваемый результат. Если результат контрольного выражения совпадает с одним из объектов в списке, то выдаётся соответствующий результат:
(case (* 2 3)
((2 3 5 7) 'prime)
((1 4 6 8 9) 'composite)) => composite
Условные выражения позволяют производить проверки значений и выбирать предусмотренный вариант:
Рассмотрим 3 способа реализации модуля числа
(define (abs x)
(cond ((> x 0) x)
((= x 0) 0)
((< x 0) (- x))))
(define (abs x)
(cond ((< x 0) (- x))
(else x)))
(define (abs x)
(if (< x 0)
(- x)
x))
Логические операции
Ряд специальных форм позволяет задать логические операции над результатами выражений:
Вычисление and продолжается до первого ложного значения. Если все подвыражения дают истинный результат, то в качестве результата всего выражения берётся результат последнего подвыражения.
(and (= 2 2) (> 2 1)) => #t
(and (= 2 2) (< 2 1)) => #f
(and 1 2 'c '(f g)) => (f g)
(and) => #t
Вычисление or продолжается до первого истинного значения. Если все подвыражения дают ложный результат, то в качестве результата всего выражения берётся результат последнего подвыражения.
(or (= 2 2) (> 2 1)) => #t
(or (= 2 2) (< 2 1)) => #t
(or #f #f #f) => #f
(or (memq 'b '(a b c)) (/ 3 0)) => (b c)
not позволяет изменить логическое значение результата на противоположное