Загрузка данных
Ниже — готовые решения для лабораторной №1Б на Scheme, соответствующие ограничениям (без `set!`, циклов и обращения по индексу).
### 1\. `uniq` — удалить соседние дубликаты
```scheme
(define (uniq xs)
(cond ((null? xs) '())
((null? (cdr xs)) xs)
((equal? (car xs) (cadr xs))
(uniq (cdr xs)))
(else
(cons (car xs) (uniq (cdr xs))))))
```
Проверка:
```scheme
(uniq '(a a b c c c d d a b a))
; => (a b c d a b a)
(uniq '(1 1 2 2 2 3 4 4 1))
; => (1 2 3 4 1)
```
### 2\. `delete` — удалить элементы по предикату
```scheme
(define (delete pred? xs)
(cond ((null? xs) '())
((pred? (car xs))
(delete pred? (cdr xs)))
(else
(cons (car xs)
(delete pred? (cdr xs))))))
```
Проверка:
```scheme
(delete even? '(0 1 2 3))
; => (1 3)
(delete zero? '(0 1 2 3))
; => (1 2 3)
```
### 3\. `polynom` — вычисление полинома (схема Горнера)
```scheme
(define (polynom coeffs x)
(define (iter xs acc)
(if (null? xs)
acc
(iter (cdr xs)
(+ (* acc x) (car xs)))))
(iter coeffs 0))
```
Проверка:
```scheme
(polynom '(3 5 2 8) 4)
; => 288
(polynom '(83 -53 74) 7)
; => 3770
```
### 4\. `intersperse` — вставить элемент между элементами списка
```scheme
(define (intersperse e xs)
(cond ((null? xs) '())
((null? (cdr xs)) xs)
(else
(cons (car xs)
(cons e
(intersperse e (cdr xs)))))))
```
Проверка:
```scheme
(intersperse 'x '(1 2 3 4))
; => (1 x 2 x 3 x 4)
```
### 5\. `all?` — все элементы удовлетворяют предикату
Без `if` и `cond`, только `and` и `or`.
```scheme
(define (all? pred? xs)
(or (null? xs)
(and (pred? (car xs))
(all? pred? (cdr xs)))))
```
Проверка:
```scheme
(all? odd? '(1 3 5 7))
; => #t
(all? odd? '(0 1 2 3))
; => #f
(all? odd? '())
; => #t
```
### 6\. `o` — композиция функций
```scheme
(define (o . fs)
(define (compose fs)
(if (null? fs)
(lambda (x) x)
(let ((f (car fs))
(g (compose (cdr fs))))
(lambda (x)
(f (g x))))))
(compose fs))
```
Проверка:
```scheme
(define (f x) (+ x 2))
(define (g x) (* x 3))
(define (h x) (- x))
((o f g h) 1)
; => -1
((o f g) 1)
; => 5
((o h) 1)
; => -1
((o) 1)
; => 1
```
### Ответы на защиту
### 1\. Где использована хвостовая рекурсия?
| Процедура | Хвостовая рекурсия |
| ----------- | ------------------ |
| uniq | Нет |
| delete | Нет |
| polynom | Да |
| intersperse | Нет |
| all? | Да |
| o | Нет |
Почему?
* В `polynom` рекурсивный вызов — последнее действие процедуры (`iter`).
* В `all?` рекурсивный вызов находится последним в выражении `and`; если предыдущая проверка истинна, результатом сразу становится рекурсивный вызов.
### 2\. Алгоритмическая сложность
| Процедура | Время | Память |
| ----------- | ------------------------------------------------- | --------------------------------------- |
| uniq | O(n) | O(n) |
| delete | O(n) | O(n) |
| polynom | O(n) | O(1) при оптимизации хвостовой рекурсии |
| intersperse | O(n) | O(n) |
| all? | O(n), в лучшем случае меньше (короткое замыкание) | O(n) |
| o | Построение O(n), вызов композиции O(n) | O(n) |
Все процедуры проходят список коэффициентов или элементов один раз, поэтому имеют линейную сложность по времени.