В Лиспекс вы часто будете работать со списками данных. Вместо использования традиционных циклов, Лиспекс предоставляет мощные функции высшего порядка для обработки списков чистым, функциональным способом. Это руководство знакомит с двумя наиболее важными функциями: map и filter.
Преобразование каждого элемента с помощью map
Что если у вас есть список чисел и вы хотите создать новый список, где каждое число удвоено? Это идеальная задача для map.
Функция map принимает функцию и список, применяет эту функцию к каждому элементу в исходном списке и возвращает новый список, содержащий результаты. Новый список всегда будет иметь то же количество элементов, что и исходный.
Синтаксис: (map FUNCTION LIST)
Пример: Удвоение чисел
(define numbers (list 10 20 30 40))
(define doubled-numbers
(map (lambda (x) (* x 2)) numbers))
;; Теперь значение doubled-numbers равно (list 20 40 60 80)
;; Исходный список `numbers` остается без изменений.
В этом примере функция (lambda (x) (* x 2)) применяется к каждому элементу и создаёт новый список.
Выбор элементов с помощью filter
А что если у вас есть список чисел, и вы хотите оставить только те, которые являются четными? Это задача для filter.
Функция filter принимает предикат (возвращает #t или #f) и список. Она применяет предикат к каждому элементу и возвращает новый список, содержащий только элементы, для которых предикат вернул #t.
Синтаксис: (filter PREDICATE_FUNCTION LIST)
Пример: Поиск четных чисел
(define numbers (list 1 2 3 4 5 6 7 8))
(define even-numbers
(filter (lambda (n) (= (modulo n 2) 0)) numbers))
;; Теперь значение even-numbers равно (list 2 4 6 8)
Совместное использование: конвейер обработки данных
Настоящая мощь проявляется, когда вы объединяете эти функции в цепочку для создания конвейера обработки данных.
Давайте решим практическую задачу: Из списка чисел найти все числа больше 5, а затем создать новый список, содержащий описательную строку для каждого из них.
(define all-scores (list 2 8 5 10 3 7))
;; Шаг 1: Оставляем только оценки больше 5.
(define high-scores (filter (lambda (score) (> score 5)) all-scores))
;; high-scores ⇒ (list 8 10 7)
;; Шаг 2: Формируем строки (используем string-append).
(define report
(map (lambda (score)
(string-append "High score: " (number->string score)))
high-scores))
;; Теперь значение report равно (list "High score: 8" "High score: 10" "High score: 7")
Вы даже можете вкладывать эти вызовы для более лаконичного кода:
(map (lambda (score) (string-append "High score: " (number->string score)))
(filter (lambda (score) (> score 5))
(list 2 8 5 10 3 7)))
Заключение
Используя map и filter, вы можете писать выразительный, читаемый и мощный код для манипулирования данными без необходимости в традиционных циклах. Этот функциональный подход является краеугольным камнем языка Лиспекс.