Применение списка функций к списку значений в Racket

#lambda #functional-programming #scheme #racket

#lambda #функциональное программирование #схема #racket

Вопрос:

Я новичок в Racket и языке scheme в целом, и мне трудно реализовать свои идеи.

В принципе, у меня есть список функций (давайте назовем это List f ) и список строк (давайте назовем это List s ). Что мне нужно сделать, так это для каждой функции в f выполнить функцию и сохранить значение в другом списке (давайте вызовем is List done ).

Например: скажем, у меня есть List A = (f1 f2) и List B = (a b c) , я бы выполнил:

 f1 a
f1 b
f1 c
f2 a
f2 b
f2 c
  

и все они будут добавлять свои значения в List done

Я также не могу использовать какую-либо форму set в racket.

Я понимаю, как это должно работать, и мог бы легко закодировать это на C или java, но схема доставляет мне проблемы.

Комментарии:

1. Обратите внимание, что '(a b c) это не список строк , это список символов . Реальный список строк будет выглядеть следующим образом: '("a" "b" "c")

Ответ №1:

В Racket есть множество встроенных процедур, которые упрощают решение проблем, связанных с манипулированием списками. Для вашего примера вы ищете for*/list :

 (define A (list string-upcase string-downcase))
(define B (list "Aa" "Bb" "Cc"))

(define done
  (for*/list ([f A] [s B])
    (f s)))
  

Выполняется итерация по всем элементам в A , присваивая каждому из них по очереди значение переменной f . И во вложенном цикле он также выполняет итерацию по всем элементам в B , присваивая каждому из них по очереди значение переменной s . В теле цикла он применяет каждую из них f ко всем s и собирает все в выходной список. Теперь done содержит ожидаемые значения:

 done
=> '("AA" "BB" "CC" "aa" "bb" "cc")
  

Если бы мы делали это вручную, используя рекурсию, было бы больше работы. Возможной реализацией было бы наличие процедуры для выполнения «внешнего» цикла, которая вызывала бы другую процедуру для выполнения «внутреннего» цикла. Третья процедура запустила бы рекурсию и объединила результаты:

 (define (outer-loop funcs params)
  (if (null? funcs)
      '()
      (cons (inner-loop (car funcs) params)
            (outer-loop (cdr funcs) params))))

(define (inner-loop f params)
  (if (null? params)
      '()
      (cons (f (car params))
            (inner-loop f (cdr params)))))

(define (apply-funcs funcs params)
  (apply append ; required to "flatten" the list of lists
         (outer-loop funcs params)))
  

Мы бы использовали это следующим образом:

 (define done (apply-funcs A B))
  

Сначала вы должны научиться решать проблемы со списком вручную, реализуя свои собственные циклы. Как только вы будете уверены, что понимаете, что делаете, потратьте некоторое время на изучение существующих процедур составления списков, итераций и понимания, идиоматического способа использования языка в реальной жизни.

Комментарии:

1. @JackKelly Я обновил свой ответ. Как вы можете видеть, решение с явной рекурсией требует довольно большой работы.