Стандартные списки Lisp нельзя добавлять в постоянное время.
Однако, если вы создадите свой собственный тип списка, вы можете сделать это. По сути, вы можете использовать тип записи (или просто минус) - давайте назовем это «заголовком» - который содержит указатели на начало и конец списка, и обновлять его каждый раз, когда кто-то добавляет в список .
Однако имейте в виду, что если вы это сделаете, списки больше не будут структурно индуктивными. то есть более длинный список не является просто расширением более короткого списка из-за задействованного дополнительного «заголовка». Таким образом, вы теряете большую часть простоты алгоритмов Лиспа, которые включают повторение в cdr
списка на каждой итерации.
Другими словами, отсутствие легкого добавления является компромиссом, позволяющим гораздо проще писать рекурсивные алгоритмы. Большинство функциональных программистов согласятся, что это правильный компромисс, поскольку добавление в чисто функциональном смысле означает, что вы должны копировать каждую ячейку во всем, кроме последнего списка - так что это больше не O (1), в любом случае.
ETA для отражения редактирования OP
Вы можете создать очередь, но с противоположным поведением: вы добавляете элементы сзади и извлекаете элементы спереди. Если вы готовы работать с этим, такую структуру данных легко внедрить в схему . (И да, легко добавлять две такие очереди в одно и то же время.)
Racket также имеет аналогичную структуру данных очереди , но использует вместо типа cons-ячейки тип записи, потому что cons-ячейки Racket являются неизменяемыми. Вы можете преобразовать свою очередь в список, используя queue->list
(со сложностью O (n)) для случаев, когда вам нужно сложить.