Una frase un tanto manida entre círculos de programación nivel medio es que el buen programador está por encima de los lenguajes que utiliza, que su mente debe estar estructurada de forma que aprender un nuevo lenguaje para él sea chascar los dedos y que, cuando se enfrenta a una tarea computacional, escoge fríamente entre los cientos de plataformas aquella que de forma más milimétricamente óptima se adapte a sus necesidades. Exagerando un poco más o un poco menos.
Pues bien, si eres fan de esta idea (y si no lo eres igualmente lo encontrarás por lo menos curioso) adorarás Rosetta Code, una wiki donde se recogen gran cantidad de problemas de programación, cada unos implementados en la mayor cantidad de lenguajes posible.
Se trata de un proyecto colaborativo, en el que cada página recoge un algoritmo, y tras una introducción y análisis inicial (complejidad computacional, utilidad, casos prácticos, etc.), pasa a un listado de implementaciones en muy diversos lenguajes. Todo perfectamente categorizado y organizado. ¿Que falta alguno que te interesa? Puedes añadirlo tú mismo. Ellos se autodefinen como una página de crestomatía de la programación.
El objetivo de fondo es adquirir perspectiva, comparar desde los distintos modos de razonar hasta las características más específicas de cada lenguaje. Al final todos los lenguajes funcionan del mismo modo: traduciéndose a instrucciones procesables por la máquina, operaciones simples con direcciones de memoria, registros y buses. Comparando lenguajes podremos, por inducción, comprender mejor cómo funcionan nuestros computadores.
Para muestra, un botón: algoritmo para generar combinaciones con repetición de un conjunto, en Java:
import com.objectwave.utility.*; import java.util.*; public class MultiCombinations { private HashSetset = new HashSet (); private Combinations comb = null; private Object[] nextElem = null; public MultiCombinations(Object[] objects, int k) throws CombinatoricException { k = Math.max(0, k); Object[] myObjects = new Object[objects.length * k]; for (int i = 0; i < objects.length; i++) { for (int j = 0; j < k; j++) { myObjects[i * k + j] = objects[i]; } } comb = new Combinations(myObjects, k); } // constructor boolean hasMoreElements() { boolean ret = false; nextElem = null; int oldCount = set.size(); while (comb.hasMoreElements()) { Object[] elem = (Object[]) comb.nextElement(); String str = “”; for (int i = 0; i < elem.length; i++) { str += (”%” + elem[i].toString() + “~”); } set.add(str); if (set.size() > oldCount) { nextElem = elem; ret = true; break; } } return ret; } // hasMoreElements() Object[] nextElement() { return nextElem; } static java.math.BigInteger c(int n, int k) throws CombinatoricException { return Combinatoric.c(n + k – 1, k); } } // class
Y en Haskell:
import Data.List combsWithRep 0 _ = [[]] combsWithRep _ [] = [] combsWithRep k xxs@(x:xs) = map (x:) (combsWithRep (k-1) xxs) ++ combsWithRep k xs countCombsWithRep k = length . combsWithRep k
¿A qué se entiende así un poquito mejor lo que puede ofrecer la programación funcional? Pues de eso se trata.
Más información | Rosetta Code