viernes, diciembre 14, 2007

Mandelbrot en F#

Una vez un profesor dijo lo siguiente. "Para aprender un lenguaje (de programación) lo primero es entender su sintaxis para lo cual basta con pegarse a leer la especificación sintáctica en BNF, el resto es conocer las API's". En cierta forma estoy de acuerdo. Sin importar que tan bueno se sea jugando con la sintaxis de un lenguaje o las posibilidades de estilo de programación que permite, aprender un lenguaje es en cierta forma conocer sus API's.

Como reto a corto plazo quiero hacer un pequeño Ray-Tracer en F#. Alguna vez hice uno en Java no fue muy difícil. Para esto hay básicamente 2 componentes

1. La parte que coja las librerías de dibujo y a partir de un bitmap pinte la imagen
2. Más importante aún, el algorítmo de Ray-Tracing

Nunca en mi vida había utilizado librerías de Microsoft. Nunca en mi vida había utilizado MSDN y puedo decir que resulta relativamente fácil. Entonces, para superar la primera parte decidí hacer un pequeño reto que pintara sobre un bitmap. Pero que iba a pintar?

Me acordé que cuando hice el Ray-Tracer en Java, saque la parte que pintaba en un bitmap de un ejemplo que pintaba el bien conocido Mandelbrot. Entonces decidí empezar por ésto. Intentar pintar el Mandelbrot.

Busca uno en wikipedia y se encuentra el algoritmito

y listo... Primer problema. él algoritmo como suele suceder es imperativo. Pues bien, F# permite código imperativo y algún día tenía que aprender.

Entonces...

let mandelbrot (x,y) =
let x0 = ref x in let y0 = ref y
let i = ref 0
while (!x0 * !x0 + !y0 * !y0 < 4.0) && (!i < 1000) do
let tmpx = !x0 * !x0 - !y0 * !y0 + x
let tmpy = 2.0 * !x0 * !y0 + y
x0 := tmpx
y0 := tmpy
i := !i + 1
if !i = 1000 then 0.0 else 1.0

Algunas generalidades sobre él código.
Para alguien cuya experiencia con código funcional haya implicado únicamente Haskell él código debe resultar espantoso. Por? Simplemente por el while. Para generar éste while se hace uso de objetos mutables (ref i, ref x0 y ref y0). A diferencia de Haskell, F# permite utilizar objetos con estado. estas ref, son casi como apuntadores. Hacen referencia a partes en memoria, lo cual implica side effects y todas las cosas "maravillosas" del mundo imperativo.

En fin... después de tener ésto implementado (Junto con la parte de System.Drawing) se genera la siguiente imagen:



En este momento la imagen es binaria. si el punto pertenece al conjunto se pinta, sino no. Nada impresionante. Una forma de hacerlo más bonito es asignando un color dependiendo de la cercanía al conjunto. Cuestión de devolver un valor no binario que se tendrá en cuenta a la hora de pintar. Yo lo hice de la siguiente manera. Reemplacé en el código anterior la última línea por ésta:


1.0/(Float.of_int (!i + 1))


El resultado:



Todo el código fuente está aquí.

martes, diciembre 11, 2007

Comenzando con F#

Si todo sale de acuerdo a lo planeado haré mi práctica trabajando en un "nuevo" lenguaje de Microsoft llamado F#. Éstas últimas semanas estuve viendo diferentes alternativas para ver donde iba a comenzar a cacharrear con el lenguaje entonces me tope con las siguientes opciones:

1. Partición Windows con Visual Estudio
2. Mono
3. Windows Virtualizado

Después de mucha pereza de instalar Windows decidí optar por instalarlo con Mono. La primera vez que lo intenté me sacaba un error con unas dlls entonces dije "Porque no virtualizo un windows y trabajo ahí? la verdad solo necesito el compilador y hago copy paste del código que escriba con mi hermoso emacs". El resultado fue ésto:



Visual estudio corriendo en un Windows virtualizado sobre KVM.

Pero lo que parecía una fantasía taaan prometedora falló en algo bien básico.

* No es posible hacer copy-paste (además no es tan cómodo como lo imaginé).

* La eficiencia se va pal carajo. La sola instalada de VS me tomó alrededor de 4 horas

* Si le hace a uno a veces falta espacio para ver el código por el montón de bobadas abiertas, Visual Estudio no colabora (en la imagen se ve)


Entonces dije "volvaaamos a intentar con mono". El asunto resulto ser mas simple de lo que pensé, para que me corriera bien solo hacía falta instalar las librerías faltantes lo cual con aptitude es muy muy fácil.

Una vez instalado hice lo primero que uno debe hacer

diegoeche@Multivac:~/Desktop/FSharp-1.9.2.9/workspace$ cat Hello.fs
printf "Hola FSharp!\n"
diegoeche@Multivac:~/Desktop/FSharp-1.9.2.9/workspace$ mono ../bin/fsc.exe Hello.fs
diegoeche@Multivac:~/Desktop/FSharp-1.9.2.9/workspace$ mono Hello.exe
Hola FSharp!


No hay monadas. Todo es simple y lleno de side-effects :P. Es decir F# no es un lenguaje puramente funcional lo que permite llamar funciones de entrada salida donde uno quiera.

Pues bien, no me podía quedar ahí y tenia que hacer algo para sentirme programando realmente en forma funcional. Entonces arregle el .emacs para trabajar con un modo para Caml llamado Tuareg porque la sintaxis de F# y Caml tiene algo de similar. Ya con un ambiente de desarrollo DE VERDAD (emacs y un compilador, que mas necesita un hombre de verdad? :P) éste fue el resultado:

open List

let rec fib x =
match x with
| 1 -> 1
| 2 -> 1
| n -> (fib (n-1)) + (fib (n-2))

let rec size x =
match x with
| [] -> 0
| x::xs -> 1 + size xs

do print_any(map (fun x -> 2 * x) [1..10])
do System.Console.WriteLine(size [1..10])


Pattern matching Recursividad, map, y una función anónima son cosas para querer empezar a trabajar ya!

:D