Ну блин
Возьмём допустмм раст, сейчас без разницы.
struct Pair<A, B> {
left: A,
right: B,
}
Вот и вся пара.
В лиспе есть функция cons, её нужно вызвать с двумя значениями и получишь то же самое
(cons 1 2)
Теперь у тебя пара из 1 и 2.
Делаешь
(car yourpair)
Получаешь левую половину - 1
Делаешь
(cdr yourpair)
Получаешь правую половину - 2
Всё просто. cons для создания, car и cdr для левого или правого значения.
Теперь следи за руками:
(cons 1 (cons 2 (cons 3 (cons 4 nil))))
У тебя цепочка и пар, у которых слева цифра, а справа ссылка на следующую пару.
Можно заюзать list
(list 1 2 3 4)
Получишь то же самое, просто чуть попроще.
Теперь главный фокус. Это очень изящно
В лиспе ВСЕ - это такой список
Каждый раз когда ты пишешь допустим
(+ 1 2 3 4 5)
Для получения суммы чисел, интерпретатор получает список у которого первый элемент - это ссылка на функцию, остальные - его параметры. То есть в лиспе нет разделения на код и данные обработываемые кодом. Код - это тоже данные. А ведь данными можно крутить и вертеть совершенно как тебе угодно.
Еще не забывай про динамическую типизацию...
Мммммм...
Короче изящно, реально гениально. Хочу пожать руку тому чуваку, который в 50-ых до этого додумался. Но вот структур данных маловато. И нормальных реализаций стандарта почти нет. Практически мёртвый язык. И конечно же не годится в продакшен.
И традиции по форматированию кода хреновые. Они зачем-то все закрывающие скобки в один ряд складывают. Сидишь, считаешь, 7 там скобок или 8