Подумайте, как семантически ведет себя Foldr.Он начинается с самого правого элемента списка и выполняет сгиб, двигаясь влево.Это означает, что в вашей лямбда-функции a
представляет элемент непосредственно слева от сложенного таким образом списка, а b
представляет результат свертывания всего справа от элемента списка a
.Имея это в виду, рассмотрим:
[(not (member? a b)) (cons a b)]
[else b]
Вы проверяете, содержит ли список b
уже a
.Если это так, то вы сбрасываете a
, сохраняя b
как есть.Это объясняет, почему ваш код сохраняет последнее (самое правое) вхождение, а не первое.Если вы хотите выполнить правильный фолд, вы должны изменить свою логику.Вам нужно как-то «очистить» b
элемента-нарушителя a
, который в нем содержится.
[(not (member? a b)) (cons a b)]
[else (cons a (purge a b))]
Таким образом, вы в конечном итоге будете сохранять только крайний левый, а не самый правый вхождение каждого уникальногоэлемент.Может быть целесообразно выполнить member?
и purge
одновременно, так как они оба должны пройти через список;это потребует дополнительного рефакторинга.
Обратите внимание, что, поскольку функция в любом случае требует O (n 2 ) времени, это действительно не повредит сложность времени, чтобы добавить O (n) обратно к версии foldl
.