mapcon передаёт функции весь остаток списка, а не только текущий элемент.
(setq Lst '(1 2 3 4))
# mapcar - получает только элемент
(mapcar
'((X)
(println "Element:" X)
X)
Lst)
# Вызовы:
# Element: 1
# Element: 2
# Element: 3
# Element: 4
# -> (1 2 3 4)
# mapcon - получает весь остаток списка (включая текущий элемент)
(mapcon
'((L)
(println "List:" L "First:" (car L) "Rest:" (cdr L))
(list (car L)))
Lst)
# Вызовы:
# List: (1 2 3 4) First: 1 Rest: (2 3 4)
# List: (2 3 4) First: 2 Rest: (3 4)
# List: (3 4) First: 3 Rest: (4)
# List: (4) First: 4 Rest: NIL
# -> (1 2 3 4)# Найти все пары соседних элементов
(de find-pairs (Lst)
(mapcon
'((L)
(when (cdr L) # Есть следующий элемент?
(list (list (car L) (cadr L)))))
Lst))
(find-pairs '(1 2 3 4 5))
# -> ((1 2) (2 3) (3 4) (4 5))
# С mapcar это невозможно, т.к. нет доступа к следующему элементу!(de handle-with-lookahead (CmdList)
(mapcon
'((L)
(let (Cmd (caar L)
Args (cdar L)
NextCmd (caadr L)) # Смотрим на следующую команду!
# Если следующая команда 'echo, добавляем вывод
(if (= NextCmd 'echo)
(list
(prinl "Next is echo, result: "
(handle Cmd Args)))
(list (handle Cmd Args)))))
CmdList))
(handle-with-lookahead
'((add 5 3)
(echo "Result")
(mul 2 4)))
# -> Next is echo, result: 8
# Result
# (8 NIL 8)# Сгруппировать последовательные числа
(de group-consecutive (Lst)
(mapcon
'((L)
(let (Curr (car L)
Next (cadr L))
(if (and Next (= (inc Curr) Next))
NIL # Продолжаем группу
(list Curr)))) # Конец группы
Lst))
(group-consecutive '(1 2 3 5 6 7 10 11))
# -> (3 7 11) - концы групп(de validate-sequence (CmdList)
(mapcon
'((L)
(let (Cmd (caar L)
NextCmd (caadr L))
# div не может быть после div (для примера)
(if (and (= Cmd 'div) (= NextCmd 'div))
(list "ERROR: Two divisions in a row!")
(list (handle Cmd (cdar L))))))
CmdList))
(validate-sequence
'((add 10 5)
(div 30 2)
(div 20 4))) # Две div подряд!
# -> (15 15 "ERROR: Two divisions in a row!")# Каждая команда знает обо всех последующих
(de process-with-future (CmdList)
(mapcon
'((L)
(let (Cmd (caar L)
Args (cdar L)
Future (cdr L)
FutureCount (length Future))
(println
"Processing:" Cmd
"Remaining commands:" FutureCount)
(list (handle Cmd Args))))
CmdList))
(process-with-future
'((add 1 2)
(mul 3 4)
(sub 10 5)))
# Processing: add Remaining commands: 2
# Processing: mul Remaining commands: 1
# Processing: sub Remaining commands: 0
# -> (3 12 5)(setq Lst '(10 20 30))
# mapcar - элемент -> результат
(mapcar '((X) (* X 2)) Lst)
# -> (20 40 60)
# mapc - элемент -> результат (но возвращает исходный список)
(mapc '((X) (println X)) Lst)
# -> (10 20 30)
# mapcan - элемент -> список, конкатенация
(mapcan '((X) (list X (- X))) Lst)
# -> (10 -10 20 -20 30 -30)
# mapcon - остаток списка -> список, конкатенация
(mapcon
'((L)
(list (car L) (length L))) # Текущий элемент + длина остатка
Lst)
# -> (10 3 20 2 30 1)
# ^ ^ ^ ^ ^ ^
# эл дл эл дл эл дл
# maplist - остаток списка -> результат
(maplist '((L) (length L)) Lst)
# -> (3 2 1)mapcon используется когда:
- Нужно сравнивать текущий элемент со следующими
- Нужно знать, сколько элементов осталось
- Нужно принимать решения на основе будущих элементов
- Нужно группировать или валидировать последовательности
- Нужен доступ к "контексту" - что идёт дальше в списке
Обычный mapcar не может этого, т.к. видит только один элемент за раз!