[ИУ9] Основы информатики

Встроенные типы данных языка Scheme

Литерный тип (character)

Слово «символ» в русском языке, применительно к типам в ЯП, двузначно: это и печатные знаки (из которых состоят строки), и некоторые имена (например, часть компилятора — таблица символов (symbol table) хранит в себе свойства именованных сущностей — переменных, функций, типов и т.д.).

По-английски первое называется «character», второе — «symbol». Чтобы нам не путаться, слово «character» в курсе «Основы информатики» мы будем называть литерой.

Литерный тип хранит в себе печатные знаки, т.е. знаки, которые вводятся с клавиатуры и выводятся на экран. Из литер состоят строки.

Сообщение о языке R5RS не описывает множество символов, реализация Racket допускает использование всех знаков Юникода (в том числе, кириллицы).

Предикат типа — (char? ch).

Литералы, т.е. то, как записываются символы в программе. Они бывают двух видов: когда символ можно представить печатным знаком, и когда нельзя. В первом случае они записываются как #\x, где x — сам знак. Например: #\a — строчная латинская a. #\! — восклицательный знак.

Во втором случае они записываются как #\‹слово›, например:

Замечу, что #\n — строчная латинская буква n.

Преобразование между символом и его числовым кодом:

(char->integer char)               → code
(integer->char code)               → char

(char->integer #\@)                → 48
(integer->char 48)                 → #\@

Сравнение символов (по числовым кодам):

(char<? ch1 ch2)
(char>? ch1 ch2)
(char<=? ch1 ch2)
(char>=? ch1 ch2)
(char=? ch1 ch2)

Сравнение без учёта регистра:

(char-ci<? ch1 ch2)
(char-ci>? ch1 ch2)
...

Преобразование регистра (??):

(char-upcase #\a)                  → #\A
(char-downcase #\Q)                → #\q
(char-upcase #\1)                  → #\1
(char-downcase #\!)                → #\!

Предикаты видов литер:

(char-whitespace? ch)    ; пробельный символ: пробел, табуляция,
                         ; перевод строки и т.д.
(char-numeric? ch)       ; цифра
(char-alphabetic? ch)    ; буква
(char-upper-case? ch)    ; большая буква
(char-lower-case? ch)    ; строчная буква

Строковой тип (string)

Строка — последовательность литер. Строка может быть пустой.

Литерал — текст, записанный в двойных кавычках. Внутри строки допустимы стандартные escape-последовательности языка Си. Примеры:

"Hello!"
"First line\nSecond line"
"Он крикнул: \"Превед!\""

Создание строк:

(make-string count char)
(make-string count)

Если символ char не указан, то создаётся строка, состоящая count символов с кодом 0 (т.е. (integer->char 0)).

(string-ref str k)                 → k-й символ строки
(string-set! str k char)           ; присваивает k-му символу

Нумерация ведётся с нуля.

Функция string-set! будет работать со строками, созданными при помощи make-string, но при этом может не работать со строками, созданными при помощи литералов.

(define s1 (make-string 3 #\a))
s1                                 → "aaa"
(define s2 "aaa")
s2                                 → "aaa"
(string-set! s1 1 #\b)
s1                                 → "aba"
(string-set! s2)                   → ОШИБКА

Строку можно создать из отдельных литер:

(string #\H #\e #\l #\l #\o)       → "Hello"

Можно преобразовать строку в список литер и наоборот:

(string->list "Hello")             → (#\H #\e #\l #\l #\o)
(list->string '(#\H #\e #\l #\l #\o))   → "Hello"

Сравнение строк (в лексинографическом порядке), с учётом регистра и без него (с суффиксом -ci):

(string=? str1 str2)
(string<? str1 str2)
...
(string-ci=? str1 str2)
(string-ci<? str1 str2)

(Для всех пяти знаков =, <, >, <=, >=.)

(string<? "Hello" "Hi")            → #t     ; #\e < #\i
(string<? "Hello" "Hell")          → #f     ; вторая строка короче

Длина строки:

(string-length "abcdef")           → 6

Выбор подстроки:

(substring "abcdef" 2 5)           → "cde"
(substring "abcdef" 2 3)           → "c"

Числовые типы

Башня числовых типов (каждый верхний предикат включает в себя все нижние):

(number? x)                        ; это число
(complex? x)                       ; комплексное число
(real? x)                          ; вещественное число
(rational? x)                      ; дробное число
(integer? x)                       ; целое число

Литералы типов:

3/4                                ; дробное число
+3.14  6.022e23   1.38e-23         ; вещественные числа
3+5i   -10-7.5i   2/3+3/4i         ; комплексные числа

Целые числа в Scheme имеют неограниченную точность, т.е. число цифр в них ограничено только памятью компьютера. Внутренне, скорее всего, небольшие числа представлены как длинные машинные числа (т.е. long в языке Си), большие числа — как массивы цифр в некоторой системе счисления (например, как unsinged int[] в системе по основанию 2³²).

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

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

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

(/ 1 3)                            → 1/3
(/ 10 3)                           → 3 1/3

В Scheme числа делятся на точные (exact) и неточные (inexact). Синтаксически неточные записываются с использованием знаков . (точка) и e (показатель степени).

Арифметические операции с точными числами дают точный ответ. Если хотя бы один из операндов неточный — результат будет неточный (приближённый).

Точные числа — целые числа, рациональные числа и комплексные числа, обе компоненты которых тоже точные (т.е. целые или рациональные).

Неточные числа — вещественные числа или комплексные с вещественными компонентами.

Предикаты:

(exact? num)
(inexcat? num)

Есть операции преобразования:

(exact->inexact num)              → ближайшее вещественное число
(inexact->exact num)              → ближайшее дробное число

Примеры:

(define pi (* 4 (atan 1)))
pi                                 → 3.141592653589793
(exact? pi)                        → #f
(inexact? pi)                      → #t
(inexact->exact pi)                → 3 39854788871587/281474976710656
(define googol 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)
googol                             → 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
(exact? googol)                    → #t
(exact->inexact googol)            → 1e+100

(exact? 1+2/3i)                    → #t
(exact? 1.0+2i)                    → #f

Функции преобразования типов

(string->number "10.3e7")          → 103000000.0
(number->string 100500)            → "100500"
(string->list "abc")               → (#\a #\b #\c)
(list->vector '(1 2 3))            → #(1 2 3)
(string->number "qwerty")          → #f