Я предпочитаю optparse getopt. Это очень декларативно: Вы говорите ему названия опций и эффектов, которые они должны иметь (например, устанавливая булево поле), и это вручает Вам, поддерживают словарь, заполненный согласно Вашим спецификациям.
Определение списка является рекурсивным.
1. The null list (empty list) is a list
2. A list is made up of an item cons a list
Итак, это списки:
1. null => () --read as empty list
2. cons 3 null => (3)
3. cons2 (cons 3 null) => (2, 3)
Последний пример, который вы указали cons 2 3, не соответствует этому определению списка, поэтому это не список. То есть cons принимает элемент и список. 3 - это не список.
cons
добавляет новый элемент в начало списка, поэтому, когда вы пишете:
(cons 1 (cons 2 (cons 3 null)))
, вы рекурсивно добавляете элементы в постоянно растущий список, начиная с с null
, который определяется как пустой список ()
. Когда вы вызываете (cons 2 3)
, вы не начинаете с пустого списка, поэтому не создаете список, добавляя 2 в его начало.
Лиспы, включая Scheme, динамически типизированы, и «лисповский способ» - это иметь множество функций над одной структурой данных, а не разные структуры данных для разных задач .
Итак, вопрос «Какой смысл требовать ноль в конце списка?» не совсем правильный вопрос.
Функция cons
не требует от вас указывать объект cons
или nil
в качестве второго аргумента. Если второй аргумент не является объектом cons
или nil
, тогда вы получаете пару, а не список, и среда выполнения печатает его не с использованием нотации списка, а с точкой.
Итак, если вы хотите создать что-то, имеющее форму списка, тогда укажите cons
список в качестве второго аргумента. Если вы хотите построить что-то еще, то укажите в качестве второго аргумента cons
что-нибудь еще.
Пары полезны, если вам нужна структура данных, в которой есть ровно два значения. С парой вам не нужен ноль в конце для обозначения ее длины, поэтому это немного более эффективно. Список пар - это простая реализация карты ключа к значению; common lisp имеет функции для поддержки таких списков свойств как часть своей стандартной библиотеки.
Итак, реальный вопрос заключается в том, «почему вы можете создавать и пары, и списки с одной и той же cons
функцией?» и ответ. «Зачем нужны две структуры данных, когда вам нужна только одна?»
Оператор cons используется для выделения пары, автомобиль которой - obj1, а cdr - obj2
(cons obj1 obj2)
Следовательно, необходимо завершить оператор cons нулевым значением, чтобы мы знали, что мы конец списка.
> (cons 1 (cons 2 3))
(1 2 . 3)
В этом примере cdr будет парой <2,3>, где 2 - автомобиль, а 3 - cdr. Не то же самое, что:
(list 1 2 3)