miércoles, 30 de septiembre de 2009

HAL también escanea

No hace mucho ;-) dejamos a nuestro HAL entregado a sus tareas rutinarias ---el sueño también forma parte de ellas---, mientras nosotros nos tomábamos unas largas vacaciones. Y es que la inmersión realizada el año pasado fue tan acelerada que había que salir a flote como fuera. Mejor retomar el hilo con algo más de moderación y de iniciar nuevas conversaciones sólo cuando la ocasión lo pida o lo permita, es decir, sin horario ni planificación prefijada.

Una ocasión de este tipo le ha surgido al autor hace poco, y lo que de ella se sigue será útil para completar lo que ya vimos sobre repeticiones y bucles, aparte de para seguir demostrando con un caso real la multiplicidad de posibles aplicaciones de la lengua de HAL a nuestras tareas habituales.

Se recordará que la instrucción for nos sirvió entonces para ordenar a HAL que recorriese las líneas de un fichero y aplicase un mismo bloque de instrucciones a cada una de ellas. En la siguiente conversación veremos un uso semejante, probablemente más frecuente, de for, en el que las unidades textuales recorridas no son líneas de ficheros, sino nombres de fichero.

Aunque ésta es probablemente la forma más frecuente de realizar tareas repetitivas en la lengua de HAL, es decir, la de recorrer unidades textuales (sean, por ejemplo, las líneas de un fichero o los nombres de una serie de nombres de fichero), hay situaciones en que es más práctico, más fácil o, simplemente, más del gusto del usuario, repetir una serie de instrucciones un número determinado de veces. Y esto es justo lo que vamos a tratar de conseguir en la conversación que hoy iniciamos.

Dedicaremos este primer artículo a especificar la tarea que motivó la conversación y la forma en que puede diseñarse un procedimiento para ejecutarla. De paso, aprenderemos a escanear un documento sin salir de la consola, cosa que quizá muchos, acostumbrados a las aplicaciones gráficas, consideren poco menos que magia negra. Aunque ---todo hay que decirlo--- esta clase de sortilegios, lanzados desde la negra interfaz de la consola, es algo a lo que deberíamos ya estar acostumbrados a estas alturas de nuestras charlas.

La tarea que nos proponemos realizar es la siguiente. Contamos con un libro voluminoso que contiene la obra completa de obras para laúd solo del gran compositor renacentista John Dowland y necesitamos extraer de él unas cuantas piezas que quepan fácil y livianamente en nuestro atril. Nos interesa, en particular, generar un fichero pdf para cada una de esas piezas.

Resulta evidente que aquí nos enfrentamos a dos problemas diferentes, en primer lugar, el de escanear las correspondientes páginas del libro y, en segundo lugar, el de generar tantos pdfs como obras queremos extraer. Nótese, en especial, que puede haber obras que consten de una sola página y obras que consten de varias páginas, y que lo que pretendemos es producir un pdf por obra y no por página.

Además, y puesto que sabemos ---el autor lo sabe, el lector debe asumirlo como presupuesto--- que HAL es capaz generar eficazmente un pdf por obra si cuenta con un pdf por página, el primero de los problemas se bifurca, a su vez, en otros dos, el del escaneo propiamente dicho y el de la conversión en pdf del resultado de dicho escaneo.

Hay que añadir, además, que, a causa tanto del tamaño del libro como de sus características físicas, será necesario retocar la imagen inicialmente escaneada para que el pdf que resulte de su conversión se adecue mejor a su posterior impresión en papel A4.

Por tanto, nuestro problema completo constará, al menos, de las siguientes partes:

  1. Escanear las páginas del libro.

  2. Retocar el resultado como convenga.

  3. Convertir los ficheros resultantes en pdfs.

  4. Unir en un único pdf los ficheros de cada página, cuando la obra conste de varias.


Podemos ser todavía más precisos si tenemos en cuenta las especificidades del proceso de escaneo. En concreto, será necesario producir una imagen donde se tengan en cuenta sólo las diferencias entre blanco y negro (lo que se llama modo Lineart) y no los tonos de grises o las divergencias de colores, que en nuestro libro no existen. Esto producirá un formato de imagen pbm. Este tipo de fichero es que el que tendremos que retocar y convertir a pdf, antes de pasar a la concatenación de los diversos pdfs. Podríamos, pues, plantear un esquema de las operaciones implicadas y los datos que se procesan dentro de ellas [Por cada página se presenta la serie de procesos por la que atravesará y los formatos de ficheros resultantes]:

/-------\ pbm /-------\ pbm /----------\ pdf
P1->|escaneo|---->|retoque|---->|conversión|-----\
\-------/ \-------/ \----------/ |
|
/-------\ pbm /-------\ pbm /----------\ pdf | /-------------\
P2->|escaneo|---->|retoque|---->|conversión|-----|--->|concatenación|->pdf
\-------/ \-------/ \----------/ | \-------------/
|
/-------\ pbm /-------\ pbm /----------\ pdf |
Pn->|escaneo|---->|retoque|---->|conversión|-----/
\-------/ \-------/ \----------/

Una inmersión en las interioridades del sistema de paquetes de HAL y de las páginas del manual ---cosas, ambas, que ya tratamos en la primera parte de esta serie--- nos permite descubrir de qué posibles herramientas disponemos. En concreto [señaladas bajo cada caja]:

/-------\ pbm /-------\ pbm /----------\ pdf /-------------\
Pn->|escaneo|---->|retoque|---->|conversión|---->|concatenación|->pdf
\-------/ \-------/ \----------/ \-------------/
scanimage unpaper convert pdftk

Cada una de estas herramientas ---o, si se quiere, de estos ayudantes de HAL--- forma parte de un paquete. A saber, en sistemas basados en Debian:

scanimage
paquete sane-utils

unpaper
paquete unpaper

convert
paquete imagemagick

pdftk
paquete pdftk


En los próximos días nos las apañaremos para construir un par de guiones que generen pdfs a partir de las páginas escaneadas y que procedan, en su caso, a su posterior concatenación. Será con la venia de estos bien predispuestos ayudantes.

HAL está esperando :-)

miércoles, 2 de septiembre de 2009

Stroustrup y la enseñanza de la programación ...

... o la ciencia de la vida.

Sí, tal rimbombante extensión del título de esta entrada ha pasado por mi cabeza, aunque la he omitido no tanto por pretenciosa, que lo es, cuanto por evitar una cabecera demasiado larga para Blogger.

¿A qué viene este embrollo? La cosa es que durante algunos días de este verano y, aprovechando, cómo no, el tan preciado descanso, me ha dado por hincar ligeramente el diente al nuevo libro del maestro Bjarne Stroustrup. Para quien no sepa quién es Stroustrup, baste decir que no sólo es el creador del lenguaje de programación C++, sino seguramente una de las personalidades más valoradas del mundillo de la informática.

Pues bien, resulta que Stroustrup ha sacado tiempo, entre sus muchas dedicaciones y responsabilidades de experto, para escribir nada menos que una introducción a la programación, un buen tocho de más de 1000 páginas titulado Programming -- Principles and Practices using C++. No he leído más que la primera parte, algo más de unas 300 páginas espléndidas en más de un sentido.

No es mi propósito hacer una reseña del libro ---por lo demás, imposible, dado que sólo he leído un fragmento---, ni siquiera una reseña de esta primera parte, que ya de por sí la merecería. Lo que, más bien, me interesa es reflexionar sobre mi experiencia al topar con sus capítulos sexto y séptimo (especialmente, el sexto).

Téngase en cuenta que mi punto de vista no es sólo el del entusiasta en estos asuntos técnicos, ni siquiera el del propenso a encontrar placer en la didáctica de la programación, sino más bien el de quien enseña algo, si bien de una índole en apariencia muy diferente. Porque, al cabo, el problema del aprendizaje va mucho más allá del objeto de la enseñanza, o sea, de la materia que se imparte, y se concentra, en particular ---si se me permite el juego de palabras, en su objetivo; y éste, cuando se entiende en su mayor generalidad, es común probablemente, a todas las formas de aprendizaje.

Pues bien, los capítulos en cuestión enseñan cosas como:

  • Diseño de una gramática abstracta para interpretar el input que procesará un programa de cálculo aritmético (una calculadora).

  • Implementación de esa misma gramática a través de funciones recursivas, mutuamente relacionadas.

  • Creación de tipos en C++ y manipulación del input a través de un tipo stream creado por el usuario.

  • etc.



Sorprende, ciertamente, que un libro de introducción ponga sobre la mesa del aprendiz una tarea de esta complejidad a unas pocas páginas de distancia de su presupuesta total ignorancia sobre la programación. Es evidente, sin duda, que Stroustrup trata a sus alumnos como adultos capaces de asumir retos difíciles desde el primer momento.

Pero lo verdaderamente sorprendente es la forma como Stroustrup plantea el ataque a este problema de programación, el diseño e implementación de una calculadora. Muchos se quedarán en la superficie y verán tan sólo un caso más ---no muy frecuente, por cierto, en textos introductorios--- de la práctica de un diseño e implementación incrementales. Pero la cosa, a mi modo de ver va más allá.

Hay algo en esas páginas que trasciende la cuestión relativa a conceptos y técnicas de programación. Dicho en pocas palabras, lo que Stroustrup una y otra vez trata de hacernos comprender es que el verdadero meollo de la programación no es otra cosa que el de pensar a fondo sobre un problema, el de acercarse, mientras hacemos el camino, a la naturaleza misma del problema inicial, cuyo sentido y complejidad se va haciendo cada vez más presente ---aunque, quizá, me atrevería a decir, nunca completa y enteramente presente---, gracias a nuestros ingenuos errores iniciales, a nuestros pasos en falso y a toda esa serie de tentativas aparentemente infructuosas y, sin embargo, imprescindibles, de las que consta todo proceso de investigación lanzado hacia lo nuevo, hacia lo desconocido.

La excelencia del maestro se mide no por la cantidad o, incluso, calidad de las cosas que enseña ---que también---, sino sobre todo porque nos hace comprender que el aprendizaje no termina nunca y que, nosotros, por muy arriba que estemos en nuestra destreza y conocimientos, somos esencialmente aprendices a la hora de enfrentarnos a nuevos retos ---los únicos que al cabo interesan---, esencialmente falibles, incorrectos, tentativos.

No es diferente lo que los grandes maestros han venido enseñando desde los albores de nuestra civilización. Piénsese, por ejemplo, en el método platónico-socrático del elenchos y la dialéctica; piénsese en el proceso de aprendizaje de cualquier artesanía compleja.

... Y piénsese ---por qué no--- en las propias cuestiones de la vida, las que nos azoran de continuo, desconcertantes, irresueltas y, a un tiempo y por ello mismo, fascinantes.

Mucho se gana ---diría, incluso, que todo se gana--- cuando se comprende que el experto no es nunca el infalible, sino el que asume con plena conciencia hasta qué punto el camino no es, ni debe ser, rectilíneo, sino más bien sinuoso, espiral incluso; y que, lejos de que ello suspenda el entusiasmo y el juicio, nos ata a la aventura del descubrimiento con la misma poderosa fuerza que el aprendiz siente en sus primeras andaduras.

Gracias, maestro Stroustrup, por recordarlo, incluso allí donde el lego quizá esperase, basado en peligrosos lugares comunes, justamente lo contrario.