uma pergunta sobre o comum de Lisp
-
27-09-2019 - |
Pergunta
Estou ficando louco com um pequeno problema aqui, continuo recebendo um erro e não consigo descobrir o porquê, o código deve alterar o intervalo de uma lista; portanto, se dermos uma lista com valores (1 2 3 4)
e queremos mudar o intervalo em 11 para quatorze, o resultado seria (11 12 13 14)
O problema é que a última função chamada scale-list
Vai devolver um erro dizendo:
Depurador digitou-Lisp Error: (Nil Nil Nil Nil Nil) ou Marker-P do tipo errado)
Alguém tem uma pista por quê? Eu uso aquamacs como editor, obrigado antecipadamente
;;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)
Solução
As definições de máxima e mínima precisam ser aprimoradas. Classificar é destrutivo. Também é errado chamar classificar com uma constante literal como '(1 2 3 4) - Novamente, o tipo é destrutivo.
Melhores definições:
(defun minimum (list)
(reduce #'min list))
(defun maximum (list)
(reduce #'max list))
Uma definição mais eficiente de intervalo:
(defun range (list)
(loop for e in list
maximize e into max
minimize e into min
finally (return (- max min))))
A lista de escala e o valor da escala também não são semelhantes a Lisp. Se você ligar para o NTH como este em uma função recursiva, algo está errado. Você deve recorrer pela lista, não pelo índice. As chamadas de valor de escala variam e o mínimo para cada chamada. Por quê?
Verifique esta variante:
;;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)
O que você pode melhorar mais? Por exemplo, eu me livraria da recursão e a substituiria pelo Mapcar.
Outras dicas
Eu posto o código porque algo deu errado ...
;;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)
Seu rastreamento de pilha real é algo como:
-(nil 0.1)
(* (- (nth ... list) (minimum list)) (- high low))
(/ (* (- ... ...) (- high low)) (range list))
(+ (/ (* ... ...) (range list)) low)
scale-value((0.1) 20 30 3)
Eu acho que você determina um elemento nº eixo errado e isso retorna nil, que atrapalha a subtração.