He resuelto 45 problemas de 4clojure.com y noté un problema recurrente en la forma en que trato de resolver algunos problemas con la recurrencia y los acumuladores.Acumuladores, conj y recursión
Trataré de explicar lo mejor que puedo hacer para terminar con soluciones fugly esperando que algunos Clojurers puedan "obtener" lo que no obtendré.
Por ejemplo, el problema 34 pide que se escriba una función (sin usar rango) tomando dos enteros como argumentos y creando un rango (sin usar el rango). Simplemente ponlo a hacer (... 1 7) y obtienes (1 2 3 4 5 6).
Ahora, esta pregunta no se trata de resolver este problema en particular.
¿Qué pasa si yo quiero para resolver esto usando recursion y un acumulador?
Mi proceso de pensamiento dice así:
Tengo que escribir una función de tomar dos argumentos, comienzo con (fn [xy])
Voy a tener que recursivo y tendré que hacer un seguimiento de una lista, usaré un acumulador, así que escribo una segunda función dentro del primero tomando un argumento adicional:
(fn [xy]
((fn g [xy acc] ...) x y '())
(al parecer no puedo formatear correctamente ese código en Clojure SO !?)
Aquí ya no estoy seguro de hacerlo correctamente: la primera función debe tomar exactamente dos argumentos enteros (no es mi llamada) y no estoy seguro: si quiero usar un acumulador, ¿puedo usar un acumulador sin crear una función anidada?
entonces quiero conj, pero no puedo hacer:
(conj 0 1)
por lo que hacen cosas extrañas para asegurarse de que tengo una primera secuencia y termino con esto:
(fn
[x y]
((fn g [x y acc] (if (= x y) y (conj (conj acc (g (inc x) y acc)) x)))
x
y
'()))
Pero entonces esto producir esto:
(1 (2 (3 4)))
lugar de esto:
(1 2 3 4)
Así que terminan haciendo un adicional aplanar y funciona pero es totalmente feo.
Empiezo a entender algunas cosas e incluso estoy empezando, en algunos casos, a "pensar" de una manera más acrítica, pero tengo un problema al escribir la solución.
Por ejemplo aquí me decidió:
- de usar un acumulador
- a Recurse incrementando x hasta que llega y
Pero termino con la monstruosidad anterior .
Hay una gran cantidad de manera de resolver este problema y, una vez más, que no es lo que busco.
lo que busco es cómo, después decidí contras/conj, utilice un acumulador, y recursivo, puedo terminar con esto (no escrito por mí):
#(loop [i %1
acc nil]
(if (<= %2 i)
(reverse acc)
(recur (inc i) (cons i acc))))
En lugar de esto :
((fn
f
[x y]
(flatten
((fn
g
[x y acc]
(if (= x y) acc (conj (conj acc (g (inc x) y acc)) x)))
x
y
'())))
1
4)
tomo es un comienzo para ser capaz de resolver algunos problemas, pero estoy un poco decepcionado por las soluciones feas que tienden a producir ...
No tenga miedo de deshacerse de las malas soluciones. Si comienza a ver que su código se vuelve difícil de manejar, dé un paso atrás y piénselo detenidamente. Cuando no * se siente * correcto, probablemente no lo es. – Jeremy
@JeremyHeiler: está bien, pero la "idea" no es tan mala, es el código de "realización"/real que es malo. Por ejemplo, el uso de la solución corta y acumulador + recursividad fue escrito por alguien que resolvió los 150 problemas de 4clojure (y algunos de ellos realmente no son triviales). Entonces mi idea no parece estar mal: pero no puedo (todavía) implementar mis ideas limpiamente. Considero que toma tiempo para que las piezas del rompecabezas caigan en su lugar: -/ –
Ciertamente sí. ¡Solo sigue practicando y jugando con el código! – Jeremy