47 | Depuración de código |
Hasta los programadores más experimentados se ven obligados a pasar por el proceso de depuración de sus códigos; esto es algo inevitable en la programación. Sin embargo, si se siguen unos cuantos principios básicos, la depuración puede ser particularmente fácil en el caso de Wolfram Language.
El primero, y más importante, de tales principios es que hay que probar cada porción del código que se escribe. Y esto se puede ir haciendo de manera casi instantánea, debido a que Wolfram Language es interactivo, a la vez que simbólico. Esto significa que aunque se hagan modificaciones muy pequeñas, el código se puede ejecutar de nuevo para ver si los ejemplos de prueba siguen funcionando. De no ser así, simplemente se arregla esa porción del código y se sigue adelante.
En ocasiones, Wolfram Language puede detectar algún posible error inmediatamente después de que se ingresa algo y, en ese caso, lo señalará marcándolo en rojo.
Después de ejecutar alguna porción de código, Wolfram Language puede indicar si algo está obviamente mal, en cuyo caso mostrará en la pantalla un mensaje a tal efecto. Por ejemplo, el código a continuación termina solicitando el primer elemento de una lista de longitud 0.
In[1]:= |
Out[1]= |
A veces Wolfram Language se topa con algo que no sabe cómo manejar, sin estar seguro de que haya algún problema. En tales casos, simplemente deja la entrada tal cual y la regresa en una forma simbólica que más tarde podría tener algún valor definitivo.
Si no se han dado valores para a, b y c, Wolfram Language simplemente regresa la entrada sin cambios:
In[2]:= |
Out[2]= |
Si se quiere generar una gráfica con partes simbólicas que no se pueden procesar, se produce una caja en color rosa:
In[3]:= |
Out[3]= |
Cuando se están construyendo funciones, es común que haya fragmentos del código que se desea probar antes de haber completado la función. Esto se puede hacer asignando valores a variables con With, que trabaja de forma parecida a Module, salvo que no permite reasignar los valores.
In[4]:= |
Out[4]= |
Si en algún caso la depuración parece tomar demasiado tiempo, esto se debe generalmente a que uno se ha equivocado al juzgar qué es lo que hace el código. En mi experiencia, lo mejor para solventar esto es simplemente analizar de manera sistemática el comportamiento del código, haciendo tablas con los resultados, generando visualizaciones, probando las afirmaciones, y todo eso.
Producir algunas gráficas para ver lo que está haciendo el código:
In[5]:= |
Out[5]= |
In[6]:= |
Out[6]= |
Se comprueba esto sistemáticamente hasta m=10:
In[7]:= |
Out[7]= |
A veces no basta con ver el resultado final de un fragmento de código; hay que asomarse también a lo que sucede al interior. Puede insertarse la función Echo en cualquier parte para ver en la pantalla resultados o valores intermedios con el código que está corriendo.
Echo muestra valores, pero no interfiere con el resultado:
In[8]:= |
1
2
3
Out[8]= |
In[9]:= |
Out[9]= |
Echo y Monitor solamente muestran cosas. Si se desea efectivamente capturar los resultados intermedios, puede usarse Sow (sembrar) y Reap (cosechar).
In[10]:= |
Out[10]= |
In[11]:= |
Out[11]= |
With[{x=value},expr] | ejecuta expr dando a x el valor value | |
Echo[expr] | muestra y regresa el valor de expr | |
Monitor[expr,obj] | muestra continuamente obj a lo largo de una ejecución | |
Sow[expr] | siembra el valor de expr para cosecharse posteriormente | |
Reap[expr] | colecciona los valores sembrados mientras se ejecuta expr |
47.1Corrija el programa Counts[StringTake[#, 2]&/@WordList[]] para contar las primeras dos letras en cada palabra, cuando se pueda. »
47.3Use Sow y Reap para obtener la lista de los casos donde se use #/2 en Nest[If[EvenQ[#], #/2, 3#+1]&, 1000, 20]. »
¿Puede surgir algún problema si se trata de ejecutar solamente un fragmento del código?
No, a menos que, por ejemplo, el código esté hecho de modo que vaya a eliminar alguna cosa. Wolfram Language tiene protección contra bucles infinitos “obviamente erróneos” y cosas de ese tipo. Si algo tarda demasiado en terminar, siempre puede abortarse. Si hay alguna preocupación seria respecto del uso de los recursos, se puede usar TimeConstrained y MemoryConstrained.
¿Hay algún error que sea muy frecuente al escribir código en Wolfram Language?
Realmente, no. El diseño del lenguaje es tal que son raros los errores que en otros lenguajes son de lo más común. Por ejemplo, los errores del tipo “faltó uno o sobró uno” son frecuentes en los lenguajes donde hay que meterse a manipular explícitamente las variables de un bucle; en Wolfram Language, esto no suele ocurrir al usar funciones para “toda la lista”, como p .ej., Table.
Si no se encuentra lo que está sucediendo mal, ¿vale la pena intentar cosas al azar?
Si se piensa que ya está cerca de descubrir lo que va mal, quizá no sea mala idea hacer en el código pequeños cambios al azar y ver qué sucede. Dado que en Wolfram Language el código simple suele ser el correcto, no es raro que se logre resolver el problema mediante un poco de búsqueda al azar.
¿Hay en Wolfram Language alguna manera de depurar interactivamente, paso a paso?
Sí (al menos con una interfaz basada en una computadora de escritorio), aunque se usa muy poco. Dada la estructura de Wolfram Language, suele ser mejor un enfoque sistemático de captura y análisis de resultados intermedios.
¿Cómo saber qué va mal cuando alguna parte de una gráfica aparece en color rosa?
Puede pasarse el cursor por encima para ver la expresión simbólica subyacente. O bien, oprimir el + para que se muestren los mensajes.
Mediante un Gray code, un ordenamiento de enteros donde solamente un dígito binario cambia en cada paso.
- Para el caso de desarrollo de software en gran escala, Wolfram Language cuenta con un marco operativo para la creación y ejecución de pruebas sistemáticas, con funciones tales como VerificationTest y TestReport.
- Un objetivo prioritario en el diseño óptimo de un lenguaje es propiciar que los usuarios escriban código de buena calidad.