Todos los ejemplos están tomados del libro SICP: http://sicpinclojure.com/?q=sicp/1-3-3-procedures-general-methods¿Cuál es la forma estándar de escribir declaraciones de definición anidadas (como en el esquema) para clojure?
Esto fue motivado por la serie de videos del MIT en LISP - http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/video-lectures/2a-higher-order-procedures/
En el esquema, se puede poner 'definir' dentro de otro 'definir':
(define (close-enough? v1 v2)
(define tolerance 0.00001)
(< (abs (- v1 v2)) tolerance))
En clojure, no es el 'vamos' declaración con la única diferencia de que se anida:
(defn close-enough? [v1 v2]
(let [tolerance 0.00001]
(< (Math/abs (- v1 v2))
tolerance)))
Pero ¿qué pasa con la reescritura en clojure algo más grande como esto ?:
(define (sqrt x)
(define (fixed-point f first-guess)
(define (close-enough? v1 v2)
(define tolerance 0.00001)
(< (abs (- v1 v2)) tolerance))
(define (try guess)
(let ((next (f guess)))
(if (close-enough? guess next)
next
(try next))))
(try first-guess))
(fixed-point (lambda (y) (average y (/ x y)))
1.0))
Este hecho funciona, pero se ve muy poco convencional ...
(defn sqrt [n]
(let [precision 10e-6
abs #(if (< % 0) (- %) %)
close-enough? #(-> (- %1 %2) abs (< precision))
averaged-func #(/ (+ (/ n %) %) 2)
fixed-point (fn [f start]
(loop [old start
new (f start)]
(if (close-enough? old new)
new
(recur new (f new)))))]
(fixed-point averaged-func 1)))
(sqrt 10)
ACTUALIZADO Mar/8/2012
¡Gracias por la respuesta!
Esencialmente 'letfn' no es muy diferente de 'let' - las funciones que se invocan deben anidarse en la definición 'letfn' (en oposición al Scheme donde las funciones se usan en el siguiente sexp después de sus definiciones y solo existente dentro del alcance de la función de nivel superior en la que está definido).
Otra pregunta ... ¿Por qué no proporciona Clojure la capacidad de hacer lo que hace el esquema? ¿Es algún tipo de decisión de diseño de lenguaje? Lo que me gusta de la organización esquema es:
1) La encapsulación de las ideas por lo que yo, como el programador tenga una idea de bloque grande lo que se están utilizando pequeños bloques - especialmente si sólo estoy usando la pequeña bloquea una vez dentro del bloque grande (por la razón que sea, incluso si los pequeños bloques son útiles por derecho propio).
2) Esto también deja de contaminar el espacio de nombres con pequeños procedimientos que no son útiles para el usuario final (escribí programas clojure, volví a ellos una semana después y tuve que volver a aprender mi código porque era en una estructura plana y sentí que estaba mirando el código de adentro hacia afuera en lugar de hacerlo de arriba hacia abajo).
3) Una interfaz de definición de método común para que pueda extraer un submétodo en particular, eliminar el error y probarlo, y pegar la versión modificada de nuevo sin demasiado alboroto.
¿Por qué no está implementado en clojure?
es una pregunta interesante, pero no creo que intente poner todo eso en una función. – Kevin