El estilo común para Lisp comenta es
- cuatro puntos y comas para comentario de toda una subsección de un archivo.
- Tres puntos y comas para introducir un solo procedimiento.
- Dos puntos y comas para una descripción de la definición de expresión/procedimiento en la siguiente línea.
- Un punto y coma para un comentario final.
Procedimiento comentarios Presentación probablemente deberían seguir el estilo de RNR documens, por lo que acaba de añadir comentarios a su procedimiento como está, sería algo como
;;; Procedure: display-n NUM ...
;; Output each argument to the screen in the order they are provided.
(define
display-n (lambda nums
(letrec ((display-n-inner (lambda (nums)
(display (car nums))
(if (not (equal? (cdr nums) '()))
(display-n-inner (cdr nums))))))
(display-n-inner nums))))
N. B. No uso tres puntos y comas para la descripción del procedimiento completo, ya que daña el párrafo de relleno en Emacs.
Ahora, sobre el código, me desharía de todo el asunto definir-variable-como-un-lambda.Sí, entiendo que esta es la forma "más pura" de definir una función, y hace una buena consistencia con los procedimientos de definición son los resultados de LET y otros procedimientos, pero hay una razón para el azúcar sintáctico, y es para hacer las cosas más legible. Lo mismo para el LETREC: solo use un DEFINE interno, que es lo mismo pero más legible.
No es un gran problema que el parámetro DISPLAY-N-INNER se llame NUMS, ya que el procedimiento es muy corto y DISPLAY-N simplemente le entrega sus NUMS de todos modos. "DISPLAY-N-INNER" es una especie de nombre cojo, sin embargo. Le daría algo con más significado semántico, o le daría un nombre simple como "ITER" o "LOOP".
Ahora sobre el lógica del procedimiento. En primer lugar, (equal? (cdr nums) '())
es tonto, y es mejor que (null? (cdr nums))
. En realidad, cuando opera en una lista completa, es mejor hacer que el caso base sea una prueba de si la lista en sí, y no su CDR, está vacía. De esta manera, el procedimiento no tendrá errores si no le pasa argumentos (a menos que desee que lo haga, pero creo que tiene más sentido para DISPLAY-N hacer nada si no obtiene nada). Por otra parte, se debe probar si a detener el procedimiento, no se si se debe continuar:
(define (display-n . nums)
(define (iter nums)
(if (null? nums)
#t ; It doesn't matter what it returns.
(begin (display (car nums))
(iter (cdr nums)))))
(iter nums))
Pero con todo esto, yo diría que el procedimiento en sí mismo no es la mejor manera de cumplir con la tarea que hace, ya está demasiado preocupado con los detalles de atravesar una lista. En su lugar, usaría el método FOR-EACH más abstracto para hacer el trabajo.
(define (display-n . nums)
(for-each display nums))
De esta manera, en lugar de un lector del procedimiento de quedar empantanados en los detalles de las CAR y CDR, se puede entender que se acabo PARA CADA-mostrará cada elemento de NUMS.
+1, todo eso es un buen consejo (especialmente la parte sobre el azúcar sintáctico). Además, tbh, de hecho, no sabía nada de 'null?', Así que eso es útil. Con respecto a cada uno, me doy cuenta de que esa es la mejor manera de abordar este problema en particular, pero entonces mi fragmento de código habría sido demasiado trivial :) – Cam
Como otra forma intermedia, ¿por qué usar el procedimiento interno? Puede hacer el recursivo externo sin pérdida de encapsulación. – Svante
@Svante: Es porque el 'nums' externo es una lista formada por todos los argumentos proporcionados a la función. Llamar recursivamente al procedimiento externo solo proporcionaría un parámetro: los argumentos en forma de lista. El problema es que 'display-n' en realidad espera múltiples argumentos, no un argumento que sea una lista, por lo que no funcionaría. Una vez dicho esto, su sugerencia sería posible usando 'apply', excepto que no estoy seguro de cuán eficiente' apply' es, por lo que aún podría no ser una buena solución. – Cam