Racket: Встроенные средства обхода списков, map
Любой список рано или поздно захочется обойти (traverse), то есть поработать с отдельными элементами. В процедурных языках используются циклы, но многие языки имеют и декларативные средства работы с коллекциями: map, filter, reduce. А ведь сами эти функции пришли в программирование через Lisp!
Racket тоже предоставляет полный набор таких функций. Ближайшие несколько уроков будут посвящены им.
map
Итак, map в Racket используется так:
(map add1 (list 1 2 3)) ; '(2 3 4)Здесь add1 — встроенная функция, добавляющая к числу единицу. Всё максимально предсказуемо: map превращает старый список в новый, применяя функцию к каждому элементу. Обход получается функциональный, потому что мы получаем новый список, не меняя старый.
Может map обходить и несколько списков одновременно: если применить map к нескольким спискам, то функция-аргумент будет применена ко всем первым элементам, затем ко всем вторым и так далее. Но map потребует от входных списков иметь одинаковую длину, иначе вы получите ошибку.
Вот так можно поэлементно просуммировать три списка:
(map +
(list 1 2 3)
(list 10 20 30)
(list 100 200 300))
; '(111 222 333)Заметьте, не потребовалось даже использовать анонимную функцию, которая складывала бы три числа, ведь функция "+" принимает произвольное количество аргументов!
Задание
Реализуйте функцию maps, которая должна принимать два списка — список функций и список списков аргументов — и возвращать список результатов применения функций к наборам аргументов. Вот как использование maps должно выглядеть:
(maps
(list
add1
string?)
(list
(list 10 20)
(list "a" 0)))
; '((11 21) (#t #f))Здесь:
'(11 21)— это результат примененияadd1к(list 10 20);'(#t #f)— это результат примененияstring?к(list "a" 0).
Полезное
Racket: Встроенные средства обхода списков, map
Любой список рано или поздно захочется обойти (traverse), то есть поработать с отдельными элементами. В процедурных языках используются циклы, но многие языки имеют и декларативные средства работы с коллекциями: map, filter, reduce. А ведь сами эти функции пришли в программирование через Lisp!
Racket тоже предоставляет полный набор таких функций. Ближайшие несколько уроков будут посвящены им.
map
Итак, map в Racket используется так:
(map add1 (list 1 2 3)) ; '(2 3 4)Здесь add1 — встроенная функция, добавляющая к числу единицу. Всё максимально предсказуемо: map превращает старый список в новый, применяя функцию к каждому элементу. Обход получается функциональный, потому что мы получаем новый список, не меняя старый.
Может map обходить и несколько списков одновременно: если применить map к нескольким спискам, то функция-аргумент будет применена ко всем первым элементам, затем ко всем вторым и так далее. Но map потребует от входных списков иметь одинаковую длину, иначе вы получите ошибку.
Вот так можно поэлементно просуммировать три списка:
(map +
(list 1 2 3)
(list 10 20 30)
(list 100 200 300))
; '(111 222 333)Заметьте, не потребовалось даже использовать анонимную функцию, которая складывала бы три числа, ведь функция "+" принимает произвольное количество аргументов!
Задание
Реализуйте функцию maps, которая должна принимать два списка — список функций и список списков аргументов — и возвращать список результатов применения функций к наборам аргументов. Вот как использование maps должно выглядеть:
(maps
(list
add1
string?)
(list
(list 10 20)
(list "a" 0)))
; '((11 21) (#t #f))Здесь:
'(11 21)— это результат примененияadd1к(list 10 20);'(#t #f)— это результат примененияstring?к(list "a" 0).
Полезное
Ваше упражнение проверяется по этим тестам
#lang racket
(require (only-in rackunit check-equal? test-begin))
(require "index.rkt")
(test-begin
(check-equal?
(maps
(list)
(list))
(list))
(check-equal?
(maps (list add1)
(list (list 0)))
(list (list 1)))
(check-equal?
(maps
(list add1 string?)
(list (list 0 100)
(list "foo" 42)))
(list (list 1 101)
(list #t #f))))Решение учителя откроется через:
20:00
