Вопрос по общему лиспу
Я схожу с ума от небольшой проблемы здесь, я продолжаю получать ошибку, и я не могу понять, почему, код должен изменить диапазон списка, поэтому, если мы дадим ему список со значениями (1 2 3 4)
и мы хотим изменить диапазон от 11 до 14, результат будет (11 12 13 14)
проблема в том, что последняя функция называется scale-list
вернет ошибку, сказав:
Введен отладчик - ошибка Лиспа: (неправильный аргумент типа номер-или-маркер-ноль)
кто-нибудь знает, почему? Я использую Aquamacs в качестве редактора заранее спасибо
;;finds minimum in a list
(defun minimum (list)
(car (sort list #'<)))
;;finds maximum in a list
(defun maximum (list)
(car (sort list #'>)))
;;calculates the range of a list
(defun range (list)
(- (maximum list) (minimum list)))
;;scales one value to another range
(defun scale-value (list low high n)
(+ (/ (* (- (nth (- n 1) list)
(minimum list))
(- high low))
(range list))
low))
;;is supposed to scale the whole list to another range
(defun scale-list (list low high n)
(unless (= n 0)
(cons (scale-value list low high n)
(scale-list list low high (- n 1)))))
(scale-list '(1 2 3 4) 21 24 4)
3 ответа
Определения максимума и минимума должны быть улучшены. СОРТ разрушительный. Также неправильно называть SORT с буквальной константой типа '(1 2 3 4) - опять же, SORT деструктивен.
Лучшие определения:
(defun minimum (list)
(reduce #'min list))
(defun maximum (list)
(reduce #'max list))
Более эффективное определение диапазона:
(defun range (list)
(loop for e in list
maximize e into max
minimize e into min
finally (return (- max min))))
SCALE-LIST и SCALE-VALUE также не похожи на Lisp. Если вы вызываете NTH как это в рекурсивной функции, значит что-то не так. Вы должны пройти по списку, а не по индексу. SCALE-VALUE вызывает RANGE и MINIMUM для каждого вызова. Зачем?
Проверьте этот вариант:
;;scales one value to another range
(defun scale-value (item low high min range)
(+ (/ (* (- item min)
(- high low))
range)
low))
;;is supposed to scale the whole list to another range
(defun scale-list (list low high)
(let ((min (minimum list))
(range (range list)))
(labels ((scale-list-aux (list)
(when list
(cons (scale-value (first list) low high min range)
(scale-list-aux (rest list))))))
(scale-list-aux list))))
(scale-list '(1 2 3 4) 21 24)
Что вы можете улучшить еще? Например, я бы избавился от рекурсии и заменил ее на MAPCAR.
Я публикую код, потому что что-то пошло не так...
;;finds minimum in a list
(defun minimum(list)
(car (sort list #'<)))
;;finds maximum in a list
(defun maximum(list)
(car (sort list #'>)))
;;calculates the range of a list
(defun range(list)
(- (maximum list) (minimum list)))
;;scales one value to another range
(defun scale-value(list low high n)
(+ (/ (* (- (nth (- n 1) list) (minimum list)) (- high low)) (range list)) low))
;;is supposed to scale the whole list to another range
(defun scale-list(list low high n)
(unless (= n 0)
(cons (scale-value list low high n) (scale-list list low high (- n 1)))))
(scale-list '(1 2 3 4) 21 24 4)
Ваша фактическая трассировка стека выглядит примерно так:
-(nil 0.1)
(* (- (nth ... list) (minimum list)) (- high low))
(/ (* (- ... ...) (- high low)) (range list))
(+ (/ (* ... ...) (range list)) low)
scale-value((0.1) 20 30 3)
Я предполагаю, что вы определили неправильный n-й элемент, и это возвращает nil, что испортило вычитание.