Ваш вопрос не был очень конкретным в отношении того, что считается. Я предполагаю, что вы хотите создать какую-то таблицу частот элементов. Есть несколько способов сделать это. (Если вы используете Racket, прокрутите вниз до нижней части для моего предпочтительного решения.)
Портативный, чисто функциональный, но многословный и медленный
Этот подход использует список ассоциаций (alist) для хранения элементов и их количества. Для каждого элемента во входящем списке он ищет элемент в списке и увеличивает значение, если оно существует, или инициализирует его значением 1, если этого не происходит.
(define (bagify lst)
(define (exclude alist key)
(fold (lambda (ass result)
(if (equal? (car ass) key)
result
(cons ass result)))
'() alist))
(fold (lambda (key bag)
(cond ((assoc key bag)
=> (lambda (old)
(let ((new (cons key (+ (cdr old) 1))))
(cons new (exclude bag key)))))
(else (let ((new (cons key 1)))
(cons new bag)))))
'() lst))
Увеличение является интересной частью. Чтобы быть чисто функциональными, мы не можем на самом деле изменить какой-либо элемент списка, но вместо этого мы должны исключить изменение ассоциации, а затем добавить эту ассоциацию (с новым значением) к результату. Например, если у вас был следующий список:
((foo . 1) (bar . 2) (baz . 2))
и хотите добавить 1 к значению baz
, вы создаете новый список, исключающий baz
:
((foo . 1) (bar . 2))
затем добавьте новое значение baz
обратно:
((baz . 3) (foo . 1) (bar . 2))
Второй шаг - это то, что делает функция exclude
, и, вероятно, самая сложная часть функции.
Портативный, емкий, быстрый, но не функционирующий
Гораздо более простой способ - использовать хеш-таблицу (из SRFI 69), а затем обновлять ее по частям для каждого элемента списка. Поскольку мы обновляем хэш-таблицу напрямую, она не является чисто функциональной.
(define (bagify lst)
(let ((ht (make-hash-table)))
(define (process key)
(hash-table-update/default! ht key (lambda (x) (+ x 1)) 0))
(for-each process lst)
(hash-table->alist ht)))
Чисто-функциональный, емкий, быстрый, но непереносимый
Этот подход использует специфичные для Racket хеш-таблицы (которые отличаются от таблиц SRFI 69), которые поддерживают чисто функциональный рабочий процесс. Как еще одно преимущество, эта версия также является самой краткой из трех.
(define (bagify lst)
(foldl (lambda (key ht)
(hash-update ht key add1 0))
#hash() lst))
Вы даже можете использовать for
понимание для этого:
(define (bagify lst)
(for/fold ((ht #hash()))
((key (in-list lst)))
(hash-update ht key add1 0)))
Это скорее признак недостатков переносимой библиотеки хеширования SRFI 69, чем какой-либо конкретный сбой схемы для выполнения чисто функциональных задач. С правильной библиотекой эту задачу можно легко и функционально реализовать.