Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Fundamentos de programación
Eduardo Andrés León y José Marı́a Fernández
4.1. Introducción
La Bioinformática puede ser un término muy amplio y difı́cil de resumir. Podrı́amos decir que es el
uso del hardware y software de un ordenador para analizar e interpertar datos biológicos. Ya seamos
matemáticos, fı́sicos, informáticos, biólogos o quı́micos, serán necesarios unos conocimientos mı́nimos
tanto de programación, como de biologı́a. Pero, antes de nada respondamos dos preguntas básicas en
bioinformática. ¿Qué es un programa? Un programa es un conjunto de instrucciones en un particular
lenguaje de programación que puede ser interpretado por un ordenador. ¿Qué es un lenguaje de pro-
gramación? Se podrı́a definir como el conjunto de instrucciones necesarias para escribir un programa.
A través de esta sintaxis podremos comunicarnos con nuestro ordenador para que realice determina-
das tareas por nosotros. Muchos de los lenguajes de programación son parecidos al lenguaje humano,
pero esta definidos de forma mucho más estricta. En este capı́tulo hablaremos más extensamente del
lenguaje de programación Perl. Pero primero veamos los tipos de lenguaje de programación existentes.
4.2.1. Abstracción
Existen dos tipos de lenguajes claramente diferenciados: los lenguajes de bajo y alto nivel. El ordenador
sólo entiende un lenguaje conocido como código binario o código máquina, consistente en ceros y unos.
Es decir, sólo utiliza 0 y 1 para codificar cualquier acción. Los lenguajes más próximos a la arquitectura
binaria de hardware se denominan lenguajes de bajo nivel y los que son más sencillos y se encuentran
más cercanos al lenguaje humano se denominan lenguajes de alto nivel.
Son lenguajes totalmente dependientes de la máquina, es decir, que los programas que se realizan con
este tipo de lenguajes no se pueden utilizar en otras máquinas al estar prácticamente diseñados a
medida del hardware, aprovechan al máximo las caracterı́sticas del mismo.
99
Dentro de este grupo se encuentran el lenguaje máquina, este lenguaje ordena a la máquina las ope-
raciones fundamentales para su funcionamiento. Consiste en la combinación de ceros y unos (código
binario) para formar las órdenes interpretables por el hardware de la computadora. Este lenguaje es
mucho más rápido que los lenguajes de alto nivel. La desventaja es que son bastantes difı́ciles de ma-
nejar y usar, además de tener códigos fuente enormes donde encontrar un fallo es casi imposible. El
lenguaje ensamblador es un derivado del lenguaje máquina y esta formado por abreviaturas de letras
y números llamadas mnemotécnicos. Con la aparición de este lenguaje se crearon los programas tra-
ductores para poder pasar los programas escritos en lenguaje ensamblador a lenguaje máquina. Como
ventaja con respecto al código máquina es que los códigos fuentes eran más cortos y los programas
creados ocupaban menos memoria. Las desventajas de este lenguaje siguen siendo prácticamente las
mismas, añadiendo la dificultad de tener que aprender un nuevo lenguaje difı́cil de probar y mantener.
Son aquellos que se encuentran más cercanos al lenguaje natural que al lenguaje máquina. Están
dirigidos a solucionar problemas mediante el uso de estructuras dinámicas de datos, algo muy utilizado
en todos los lenguajes de programación. Son estructuras que pueden cambiar de tamaño durante la
ejecución del programa. Nos permiten crear estructuras de datos que se adapten a las necesidades reales
de un programa.
Se trata de lenguajes independientes de la arquitectura del ordenador. Por lo que, en principio, un
programa escrito en un lenguaje de alto nivel, puede migrar de una máquina a otra sin ningún tipo de
problema.
Estos lenguajes permiten al programador olvidarse por completo del funcionamiento interno de la
máquina para la que están diseñados. Tan sólo necesitan un traductor que entienda tanto el código
fuente como las caracterı́sticas de la máquina.
4.2.2. Ejecución
La elección del lenguaje de programación nunca deberı́a ser aleatoria o basada únicamente en prefe-
rencias personales. Ya sea más o menos fácil el aprender un determinado lenguaje de programación,
lo ideal es usar el más óptimo dependiendo de la tarea que vayamos a realizar. El rendimiento a la
hora de ejecutar un determinado programa, puede ser uno de los criterios a tener en cuenta. El tiempo
empleado en leer o “parsear ” un fichero (que podrı́amos definir como obtener información a partir de
datos, los cuales aparecen en un determinado formato no enriquecido), por ejemplo en formato FASTA,
o en realizar un alineamiento de secuencias, depende en gran medida del lenguaje de programación a
usar [1]. Lenguajes como C o C++ , son conocidos por su alto rendimiento en cuanto a uso de pro-
cesador como a uso de memoria RAM, sin embargo son lenguajes de alto nivel que a priori sin ser
informáticos, pueden resultar complicados de dominar. En la mayorı́a de situaciones deberemos buscar
un compromiso entre la dificultad y el tiempo a emplear en escribir el programa y el rendimiento del
mismo. No tiene sentido aprender un nuevo lenguaje para ahorrar una hora de cálculo. Si tenemos
en cuenta el estudio sobre los lenguajes más usados en el campo de la bioinformática en el año 2012,
mostrado en la Figura 4.1, podemos comprobar como R (lenguaje de programación para el análisis
estadı́stico) junto a Perl y Python, son los más usados.
Un buen bioinformático, deberı́a ser capaz de programar en varios lenguajes y usar uno u otro en
función de sus necesidades y los recursos computacionales a su disposición, ası́ como los algoritmos a
usar y el tipo de datos de partida. En el presente texto escogeremos Perl como modelo de lenguaje de
programación de alto nivel para explicar su funcionamiento a lo largo del capı́tulo. Veremos los tipos
de datos con los que trabaja, esencialmente escalares, arrays y hashes. A su vez veremos estructuras
de control, como bucles y sentencias condicionales y expresiones regulares entre otros.
Mirando al pasado de la informática, la forma de interactuar con los ordenadores de la época era
con una consola fı́sica (Figura 4.2). Dicha consola fı́sica era un teclado unido a una pantalla, que
estaba conectado por puerto serie al ordenador. Los contenidos que era capaz de mostrar esa consola
eran únicamente textuales y monocromáticos, sin ninguna capacidad gráfica. Toda interacción con el
ordenador era a través de esa consola, tecleando órdenes y leyendo la salida proporcionada por esas
órdenes.
Esta forma de trabajo, aunque en principio parece arcaica, sigue vigente, debido a que es mucho más
sencillo realizar el mismo conjunto de operaciones sobre muchos ficheros desde la consola que desde
el entorno gráfico. Dicho conjunto de operaciones se pueden automatizar mediante la preparación de
un lote de órdenes (o script), que es un guión de operaciones que dicta qué operaciones se realizan
sobre los ficheros, y en qué orden. Actualmente, casi todos los sistemas operativos y entornos gráficos
proporcionan programas de consola virtual que permiten seguir con esta forma de trabajo.
Una consola de texto (ya sea fı́sica o virtual) no sirve de nada sin un intérprete de órdenes para la lı́nea
de comandos (o shell ). Una shell es un programa que entiende una serie de órdenes textuales comunes,
como por ejemplo cambiar de directorio, mostrar los contenidos de un directorio, copiar, mover y borrar
ficheros y directorios, y ejecutar programas.
En los sistemas Windows, la shell usada se llama ‘cmd’, mientras que para los sistemas derivados
de UNIX, como por ejemplo Linux o Mac OS X, las shells que se usan principalmente son ‘bash’ y
‘tcsh’. Todas estas shells disponen de su propio lenguaje de script, que permite no sólo ejecutar una
serie de órdenes una detrás de otra, sino también operaciones más complejas como aplicar las mismas
operaciones a cada uno de los ficheros de un directorio, y manipular variables de entorno. Las variables
de entorno rigen, entre otras cosas, dónde buscar los programas a ser ejecutados en la shell. La Tabla 4.1
muestra algunas de las operaciones básicas que se pueden realizar en una shell.
4.4.2. Instalación
Instalación Linux
Perl está instalado por defecto en las distribuciones más populares de GNU/Linux incluyendo Gentoo,
Slackware, Mandriva, Debian, RedHat, SUSE y Ubuntu. En el caso de que quisiéramos instalarlo,
tendrı́amos dos opciones:
1. Usar binarios precompilados. Un binario precompilado no es mas que el intérprete de perl, ası́ co-
mo las librerı́as y los módulos necesarios para que funcione. Su instalación implica descargar el
archivo, descomprimirlo y ejecutarlo desde la propia página de Perl3 o la versión ofrecida por la
empresa ActiveState4 .
2. Compilar perl desde el código fuente. El código fuente, no es más que el código escrito direc-
tamente por el autor, para que nosotros creemos nuestros propios binarios. Las instrucciones a
ejecutar en consola para instalar la versión 5.14 son las siguientes :
$ wget http://www.cpan.org/src/5.0/perl-5.14.2.tar.gz
$ tar -xzf perl-5.14.2.tar.gz
$ cd perl-5.14.2
$ ./Configure -des -Dprefix=$HOME/localperl
$ make
$ make test
$ make install
Instalación en MacOS
En el caso de los sistemas operativos de Apple, Perl viene incluido por defecto y no es necesario
hacer nada especial. Simplemente abrir la consola y empezar a programar. En el caso de necesitar
una instalación propia, ésta instalación, ya sea a través de binarios o del código fuente, es igual a la
explicada anteriormente para los ordenadores que usan Linux. Después de todo, ambos proceden del
sistema operativo UNIX.
3
Página oficial de Perl. http://www.perl.org
4
ActiveState Perl. http://www.activestate.com
Instalación en Windows
Los usuarios de Windows normalmente instalan una distribución binaria de Perl. Compilar Perl desde el
código fuente bajo Windows es posible, pero la mayorı́a de las instalaciones no disponen del necesario
compilador de C. La opción más sencilla es descargar un fichero ejecutable desde la página web de
ActiveState4 que nos instalará todo lo necesario para que Perl funcione desde el interfaz de comandos
propio de Windows. El sistema de emulación Cygwin5 también proporciona otra forma de ejecutar Perl
bajo Windows. Cygwin proporciona en entorno parecido al Unix en Windows que incluye ‘gcc’, por lo
que compilar Perl desde el código es una opción accesible para los usuarios que prefieren esta opción.
A lo largo de esta sección, iremos profundizando en los detalles más relevantes de Perl. Empezando por
el programa más sencillo. En Perl, el programa canónico ‘Hola mundo’ es:
#!/usr/bin/perl
print "Hola mundo\n"; # Imprime "Hola mundo"
La primera lı́nea contiene el “shebang” (par de caracteres que identifica el texto que sigue), que le
indica al sistema operativo dónde encontrar el intérprete de Perl. La segunda imprime el string “Hola
mundo” y un carácter de nueva lı́nea. Todos los comandos de Perl terminan en punto y coma (‘;’). Se
pueden insertar comentarios en el código con el sı́mbolo almohadilla (‘#’), todo lo que siga a dicho
sı́mbolo no será leı́do al ejecutar el código. El shebang es la forma normal para invocar al intérprete
en los sistemas Unix. Los sistemas Windows pueden seguir utilizándolo o pueden asociar la extensión
de archivo ‘.pl’ con el intérprete Perl. Algunos editores de texto también usan la lı́nea shebang como
una pista sobre el modo de trabajo en que deben operar. Si el programa es ejecutado por Perl y no
invocado por el shell, la lı́nea que empieza por el shebang es parseada para interpretar las opciones. En
otro caso, es ignorada.
Una caracterı́stica de Perl es que reconoce el tipo de dato de una variable. Perl convertirá los strings
en números y viceversa dependiendo del contexto en que sean usados. En el siguiente ejemplo (??) los
strings ‘$n’ y ‘$m’ son tratados como números cuando son argumentos del operador suma. Este código
imprime el número ‘5’, desechando cualquier información no numérica de la operación y dejando los
valores de las variables intactos.
$n = "3 casas";
$m = "20 motos";
print $n + $m; # Resultado '5'
Una lista se define listando sus elementos, separados por comas y rodeados por paréntesis donde ası́ sea
requerido por la precedencia de los operadores:
@numeros = (32, 45, 16, 5);
Los elementos individuales de una lista son accedidos utilizando un ı́ndice numérico, dentro de corchetes.
Valores individuales en un hash son accedidos utilizando la correspondiente clave, dentro de llaves. El
sı́mbolo ‘$’ identifica que el elemento accedido es un escalar.
$numeros[2];
$color{'moto'};
Múltiples elementos pueden ser accedidos usando en su lugar el sigilo ‘@’ (identificando el resultado
como una lista).
@numeros[2, 3, 1] # tres elementos de @puntuaciones
@color{'coche', 'moto'} # dos valores de %color
El número de elementos en un array puede ser obtenido mediante la función ‘scalar’ o con la ayuda
del sigilo ‘$#’ éste último da el ı́ndice del último elemento dentro del array, que será una unidad menor
que el número de elementos puesto que el ı́ndice del primer elemento del array es ‘0’.
scalar @amigos; # número de elementos en @amigos
$#amigos; # ı́ndice del último elemento
Estructuras de control
Perl tiene varias clases de estructuras de control, estructuras de control orientado al bloque o bucles,
similar a los de los lenguajes de programación C y Java. Y estructuras condicionales. Las condiciones
están rodeadas por paréntesis y los bloques subordinados por llaves:
while ( condición ) {... }
while ( condición ) {... } continue {... }
for ( expresión inicial; expresión condicional; expresión incremental ) {... }
foreach var ( lista ) {... }
foreach var ( lista ) {... } continue {... }
if ( condición ) {... }
if ( condición ) {... } else {... }
if ( condición ) {... } elsif ( condición ) {... } else {... }
Las palabras clave de control de flujo ‘next’, ‘last’, ‘return’ y ‘redo’ son expresiones, por lo que
pueden ser usadas con los operadores cortocircuito. Perl también tiene dos construcciones implı́citas
para bucles:
resultados = grep {... } lista
resultados = map {... } lista
‘grep’ devuelve todos los elementos de lista en que el bloque subordinado evalúa a verdadero. ‘map’
evalúa el bloque subordinado por cada elemento de lista y devuelve una lista de los valores resultantes.
Estas construcciones permiten un estilo simple de programación funcional. No hay declaración ‘switch’
(salto multi-camino) en Perl 5. La documentación Perl describe media docena de formas de conseguir
el mismo efecto usando otras estructuras de control. Existe sin embargo un módulo Switch, que
proporciona la funcionalidad modelada para el próximo Perl 6. Perl incluye una declaración ‘goto
¡etiqueta¿’, pero es usada raramente. Las situaciones donde en otros lenguajes se utiliza ‘goto’ no
ocurren tan a menudo en Perl debido a sus amplias opciones de control de flujo. Existe también una
declaración ‘goto &sub’ que realiza una llamada final. Termina la subrutina actual e inmediatamente
llama a la subrutina especificada. Esto se usa en situaciones donde una nueva subrutina puede realizar
una gestión de la pila más eficiente que el propio Perl (porque tı́picamente no se requiere ningún cambio
en la pila actual), y en una recursión muy profunda este tipo de llamadas puede tener un sustancial
impacto positivo en el funcionamiento porque evita la sobrecarga de la gestión contexto/pila en el
momento de retornar.
Subrutinas
Las subrutinas se definen con la palabra clave ‘sub’ e invocadas simplemente nombrándolas. Si la
subrutina en cuestión no ha sido todavı́a declarada, es necesario, para el proceso de análisis sintáctico,
poner los paréntesis.
foo(); # paréntesis necesarios aquı́...
sub foo {... }
foo; # pero no aquı́
Una lista de argumentos pueden ser indicados después del nombre de la subrutina. Los argumentos
pueden ser escalares, listas o hashes.
foo($x, @y, %z);
Los parámetros de una subrutina no necesitan ser declarados, ni en número ni en tipo, de hecho, pueden
variar en cada llamada. Los arrays son expandidos a sus elementos, los hashes a una lista de pares
clave/valor y todo el conjunto es pasado a la subrutina como una indiferenciada lista de escalares.
Cualesquiera de los argumentos pasados están disponibles para la subrutina en el array especial ‘@ ’.
Los elementos de ‘@ ’ son asociados a los argumentos actuales; cambiando un elemento de ‘@ ’ cambia el
argumento correspondiente. Los elementos de ‘@ ’ pueden ser accedidos con los subı́ndices de la forma
normal:
$_[0], $_[1]
Sin embargo, el código resultante puede ser difı́cil de leer y los parámetros tener una semántica de pase
por referencia, que puede resultar algo no deseable. Un modismo común es asignar ‘@ ’ a una lista de
variables con nombres:
my($x, $y, $z) = @_;
Esto afecta tanto a la mnemónica de los nombres de los parámetros como a la semántica de los valores
pasados por valor. La palabra clave ‘my’ indica que las siguientes variables están léxicamente embebidas
en el bloque que las contienen. Otro modismo es sacar los parámetros de ‘@ ’. Esto es muy común cuando
la subrutina toma un sólo argumento:
my $x = shift; # Si no se dice nada, nos referimos a @_
Si la subrutina no sale vı́a declaración ‘return’, entonces devuelve la última expresión evaluada en el
cuerpo de la subrutina. Arrays y hashes en el valor de retorno son expandidos a una lista de escalares,
igual que si fueran argumentos de una función. La expresión devuelta es evaluada en el contexto de la
llamada de la subrutina; esto puede sorprender al desprevenido.
sub lista { (4, 5, 6) }
sub array { @x = (4, 5, 6); @x }
El lenguaje Perl incluye una sintaxis especializada para escribir expresiones regulares y el intérprete
contiene un motor para emparejar strings con expresiones regulares. El motor de expresiones regulares
usa un algoritmo de vuelta atrás (backtracking), extendiendo sus capacidades desde el simple empare-
jamiento de patrones simples con la captura y sustitución de strings. El motor de expresiones regulares
se deriva de ‘regex’, escrito por Henry Spencer. La sintaxis de expresiones regulares fue originalmente
tomada de las expresiones regulares de Unix 8. Sin embargo, se diferenció ya antes del primer lan-
zamiento de Perl y desde entonces ha ido incorporando muchas más caracterı́sticas. Otros lenguajes
y aplicaciones están adoptando las expresiones regulares de Perl denominadas PCRE en vez de las
expresiones regulares POSIX, incluyendo PHP, Ruby, Java y el Servidor HTTP Apache. El operador
‘m//’ (empareja) permite comprobar un emparejamiento por medio de una expresión regular (para
abreviar, el precedente ‘m’ puede ser omitido). En el caso más simple, una expresión como:
$x = ∼ m/abc/;
evalúa a verdadero si y sólo si el string ‘$x’ empareja con la expresión regular ‘abc’. Partes de la
expresión regular pueden ser incluidas entre paréntesis y las partes correspondientes de un string
emparejado son capturadas. Los strings capturados son asignados de forma secuencial a las variables
internas ‘$1’, ‘$2’, ‘$3’,... y una lista de strings capturados se devuelve como valor del emparejamiento:
$x = ∼ m/a(.)c/; # captura el carácter entre 'a' y 'c' y lo guarda en $1
Las expresiones regulares en Perl pueden tomar unos modificadores. Son sufijos de una sola letra que
modifican el significado de la expresión:
$x = ∼ m/abc/i; # emparejamiento independientemente de si están en mayúscula o min
úscula
$x = ∼ s/abc/aBc/g; # búsqueda y reemplazo recursivo global (a lo largo de todo el
string)
Las expresiones regulares pueden ser densas y crı́pticas. Esto es porque la sintaxis de las expresiones
regulares es extremadamente compacta, generalmente usando caracteres sueltos o pares de caracteres
que representan sus operaciones.
Un uso común de las expresiones regulares es el de especificar delimitadores de campos al operador
‘split’:
@palabras = split m/,/, $linea; # divide $lı́nea en valores separados por comas.
El operador ‘split’ complementa la captura de string. La captura de string devuelve las partes que
emparejan con una expresión regular y ‘split’ devuelve las partes que no emparejan.
Ejemplos simples
Ejemplo 1. Cómo convertir un secuencia de DNA en RNA (Código 4.1). Como sabéis, el DNA está com-
puesto de 4 tipo de nucleótidos denominados, adenina (A), guanina (G), citosina (C) y timina (T)
(Sección 7.3). En el caso del RNA la base equivalente a la timina (T) es el uracilo (U).
Ejemplo 2. Cómo convertir un secuencia de RNA en un fichero en DNA (Código 4.2). En este caso,
vamos a hacer el caso contrario, es decir convertir una secuencia de RNA en DNA. La complicación
viene por el hecho de leer la secuencia directamente desde un fichero en nuestro ordenador. Lo primero
que necesitamos es un fichero con una secuencia de RNA. Por lo tanto usando un editor de texto,
creamos un fichero llamado ‘secuenciaRNA.txt’, cuyo contenido sea el siguiente:
UUACGGCGGAGCUUUGACGCUACGAUCGAUCG
Ejemplo 3. Cómo obtener la secuencia complementaria a una secuencia de DNA (Código 4.3). Lo
primero que necesitamos es de nuevo un fichero con una secuencia de DNA. Por lo tanto usando un
editor de texto, creamos un fichero llamado ‘secuenciaDNA.txt’, cuyo contenido sea el siguiente:
TGTGGTACGTACGACAAACGTCGTACGTA
¿Que es BioPerl?
BioPerl es una colección de módulos de Perl que facilitan el desarrollo de scripts en Perl para apli-
caciones de bioinformática [3]. Ha desempeñado un papel integral en el Proyecto Genoma Humano.6
Se trata de un activo proyecto de software libre apoyado por la Open Bioinformatics Foundation. La
primera versión estable fue lanzada el 11 de junio de 2002; la última estable (en términos de la API)
es la 1.6.9, lanzada en abril de 2011. La versión 1.6.0 es considerada la más estable (en términos de
errores) y la recomendada para el uso diario. También hay lanzamientos periódicos producidos por
desarrolladores. Con el fin de aprovechar BioPerl, el usuario necesita una comprensión básica del len-
guaje de programación Perl que incluya una comprensión de cómo Perl utiliza las referencias, módulos,
objetos y métodos.
6
BioPerl en Wikipedia. http://es.wikipedia.org/wiki/BioPerl
Instalación de BioPerl
En la introducción de este capı́tulo se explicó lo que es una clase, un objeto y una función (Subsec-
ción 4.2.3), ahora en este apartado lo veremos con ejemplos. Para ellos vamos a usar la clase secuencia
‘Bio::Seq’, para crear un objeto que contenga nuestra secuencia de interés. Una vez creado, usaremos
varias funciones de BioPerl para procesar la secuencia.
$seq = Bio::Seq->new(
-seq => 'ATGGGGGTGGTGGTACCCT',
-id => 'mi_secuencia');
Podemos trabajar con el objeto secuencia usando métodos propios de BioPerl. En el siguiente ejemplo,
reescribiremos el Código 4.3 usando métodos de BioPerl.
En el ejemplo anterior, nosotros mismos tuvimos que programar un bucle inverso para recorrer la
secuencia de forma reversa y para obtener los nucleótidos complementarios creamos un hash con las
equivalencias. En el caso de BioPerl, sólo tenemos que aplicar el método ‘revcom’ a nuestro objeto
secuencia y ya lo tenemos.
Ejemplo 1. El primer ejemplo, nos servirá para crear la secuencia de proteı́na a partir de un secuencia
de DNA (Código 4.6).
Como ya hemos comentado a lo largo del capı́tulo, Perl es un lenguaje maduro y ampliamente utilizado
en bioinformática. Es fácil de aprender y su sintaxis es similar al lenguaje inglés hablado, lo que le hace
especialmente útil para aquellos con poca experiencia en el mundo de la programación.
De Perl podemos destacar principalmente: la enorme utilidad de las expresiones regulares (PCRE)
(Sección 4.4.3) y el repositorio CPAN (Subsección 4.4.1) que contiene infinidad de módulos y funciones
que completan al lenguaje y nos ayudan a la hora de realizar casi cualquier tarea, incluyendo BioPerl
(Subsección 4.4.4) para la realización de numerosas tareas bioinformáticas.
4.5. Bibliografı́a
[1] M. Fourment and M. R. Gillings. A comparison of common programming languages used in bioinformatics., volume 9.
2008.
[2] R. L. Schwartz and L. Wall. Programming Perl. jan 1991.
[3] J. E. Stajich, D. Block, K. Boulez, S. E. Brenner, S. A. Chervitz, C. Dagdigian, G. Fuellen, J. G. R. Gilbert, I. Korf,
H. Lapp, H. Lehväslaiho, C. Matsalla, C. J. Mungall, B. I. Osborne, M. R. Pocock, P. Schattner, M. Senger, L. D.
Stein, E. Stupka, M. D. Wilkinson, and E. Birney. The bioperl toolkit: Perl modules for the life sciences. Genome
Research, 12(10):1611–1618, oct 2002.