<?xml-stylesheet type="text/xsl" href="http://ajayu.memi.umss.edu.bo/tati/weblog/rss/rssstyles.xsl"?>
<rss version='2.0'   xmlns:dc='http://purl.org/dc/elements/1.1/'>
    <channel xml:base='http://ajayu.memi.umss.edu.bo/tati/weblog/'>
        <title><![CDATA[Comunidad Haskell San Simon : Weblog]]></title>
        <description><![CDATA[El weblog para Comunidad Haskell San Simon, alojado en Ajayu.]]></description>
        <generator>Elgg</generator>
        <link>http://ajayu.memi.umss.edu.bo/tati/weblog/</link>        
        <item>
            <title><![CDATA[Men's Discount Christian Louboutin shoes, "Sha Hui" fashion circles.]]></title>
            <link>http://ajayu.memi.umss.edu.bo/tati/weblog/2466.html</link>
            <guid isPermaLink="true">http://ajayu.memi.umss.edu.bo/tati/weblog/2466.html</guid>
            <pubDate>Fri, 03 Sep 2010 02:39:49 GMT</pubDate>
		<dc:subject><![CDATA[Haskell]]></dc:subject>
		<dc:subject><![CDATA[Comunidad Haskell]]></dc:subject>
		<dc:subject><![CDATA[Programacion Funcional]]></dc:subject>
            <description><![CDATA[<p><span class="blog_post_source"><a href="http://blog.comunidadhaskell.org/pg/blog/claire/read/315/mens-discount-christian-louboutin-shoes-sha-hui-fashion-circles">http://blog.comunidadhaskell.org/pg/blog/claire/read/315/mens-discount-c</a></span></p> <p>&nbsp;&nbsp;&nbsp;&nbsp; Ms. high heels is no longer the monopoly of men has become a <a href="http://www.overheels.com/">Discount Christian Louboutin shoes</a> are now loyal customers. Latest baked spring and summer 2011 Milan  Fashion Week, the luxury brand Prada has released their latest design  men's shoes. These Christian Louboutin Peep-toe might be called the  platform shoes more suitable for the design concept is to increase the  vertical height, lengthen the leg line, make a man more confident.</p>
<p>&nbsp;&nbsp;&nbsp; In  fact, ladies and for men to wear <a href="http://www.overheels.com/christian-louboutin-sandals-c-4.html">Christian Louboutin Sandals</a> really do not care too much about. You know, Christian Louboutin  Evening first originally designed for men. Early 16th century, people  riding knight to solve the foot in the stirrup sliding problems, which  padded the heel. French monarch Louis XIV's personal interest in this  achievement was later popular inChristian Louboutin Pumps, but it was  mainly all male wearing high heels.</p>
<p>&nbsp;&nbsp;&nbsp; But the success of women seeking  high heels toward the throne today, the men had wanted to take back the  "throne" is not impossible. Cone with, and ankle boots, this year's  men's high heels in no way inferior to women. Prada's design has taken  the attitude of compromise than "Hentian high" in height and bizarre <a href="http://www.overheels.com/christian-louboutin-wedges-c-6.html">Christian Louboutin Wedges</a>,  shoes like normal people more likely to be accepted, with the Prada  shoes of complex designs, for men high-heeled shoes decorated in simple  style brings out the man's masculinity. If you're really not satisfied  with height, then select pairs of high heels like a man now!</p>]]></description>
        </item>
                
        <item>
            <title><![CDATA[Hey just signed up]]></title>
            <link>http://ajayu.memi.umss.edu.bo/tati/weblog/2465.html</link>
            <guid isPermaLink="true">http://ajayu.memi.umss.edu.bo/tati/weblog/2465.html</guid>
            <pubDate>Wed, 01 Sep 2010 13:57:09 GMT</pubDate>
		<dc:subject><![CDATA[Comunidad Haskell]]></dc:subject>
		<dc:subject><![CDATA[Programacion Funcional]]></dc:subject>
		<dc:subject><![CDATA[Haskell]]></dc:subject>
            <description><![CDATA[<p><span class="blog_post_source"><a href="http://blog.comunidadhaskell.org/pg/blog/rsriamakgi/read/312/hey-just-signed-up">http://blog.comunidadhaskell.org/pg/blog/rsriamakgi/read/312/hey-just-si</a></span></p> <p>Hello, nice site. Had myself signed up. Nice</p>]]></description>
        </item>
                
        <item>
            <title><![CDATA[L-System 2]]></title>
            <link>http://ajayu.memi.umss.edu.bo/tati/weblog/2427.html</link>
            <guid isPermaLink="true">http://ajayu.memi.umss.edu.bo/tati/weblog/2427.html</guid>
            <pubDate>Sun, 16 May 2010 03:34:15 GMT</pubDate>
		<dc:subject><![CDATA[Haskell]]></dc:subject>
		<dc:subject><![CDATA[Comunidad Haskell]]></dc:subject>
		<dc:subject><![CDATA[Programacion Funcional]]></dc:subject>
            <description><![CDATA[<p><span class="blog_post_source"><a href="http://blog.comunidadhaskell.org/pg/blog/carliros/read/152/lsystem-2">http://blog.comunidadhaskell.org/pg/blog/carliros/read/152/lsystem-2</a></span></p> <p>Hice unos avances en este <a href="http://devel.comunidadhaskell.org/l-system"  target="_blank"  title="proyecto l-system">proyecto</a>, implemente la parte de movimiento turtle.</p>
<p>Turtle, es un lenguaje para generar recorridos. Basicamente turtle tiene un estado y comandos a ejecutar sobre el estado.</p>
<p>El estado es la posicion (x,y) del objeto, la distacia a recorrer y un angulo que guia la direccion.</p>
<p>Los comando son:<br />F &nbsp;-&gt; avanzar adelante y dibujar una linea entre el punto del estado y el nuevo generado por la distancia y angulo.<br />f &nbsp;-&gt; avanzar adelante pero sin dibujar ninguna linea.<br />+ -&gt; incrementar el angulo de estado con otro angulo constante.<br />- -&gt; decrementar el angulo del estado con otro angulo constante.</p>
<p>Entonces, la anterior version generaba el resultado de un sistema L, ahora en esta nueva version, genero elementos del lenguaje turtle. Y una ves generados estos elementos, los interpreto con una libreria grafica, wxhaskell.</p>
<p>Les dejo algunas imagenes de los resultados obtenidos:</p>
<p><img src="/action/file/download?file_guid=149"  border="0"  alt="lsystem-koch"  width="839"  height="762" /></p>
<p>&nbsp;</p>
<p><img src="/action/file/download?file_guid=150"  border="0"  alt="kochil" /><img src="/action/file/download?file_guid=151"  border="0"  alt="koche"  width="287"  height="285" /></p>]]></description>
        </item>
                
        <item>
            <title><![CDATA[L-System]]></title>
            <link>http://ajayu.memi.umss.edu.bo/tati/weblog/2426.html</link>
            <guid isPermaLink="true">http://ajayu.memi.umss.edu.bo/tati/weblog/2426.html</guid>
            <pubDate>Sat, 15 May 2010 07:57:20 GMT</pubDate>
		<dc:subject><![CDATA[Haskell]]></dc:subject>
		<dc:subject><![CDATA[Comunidad Haskell]]></dc:subject>
		<dc:subject><![CDATA[Programacion Funcional]]></dc:subject>
            <description><![CDATA[<p><span class="blog_post_source"><a href="http://blog.comunidadhaskell.org/pg/blog/carliros/read/148/lsystem">http://blog.comunidadhaskell.org/pg/blog/carliros/read/148/lsystem</a></span></p> <div>
<h1>L-System</h1>
<p>Hoy por la noche, cuando navegaba por la red me encontre con algo interesante. Y decidi iniciar un proyecto peque&ntilde;o, un <a href="http://devel.comunidadhaskell.org/l-system">L-System</a> en Haskell.</p>
<p>Este proyecto me trae recuerdos cuando estaba en la materia de Interfaces de Usuario con el Lic. Boris Calancha, en la que desarrollamos fractales con Java, de una forma recursiva. En aquel entonces no tenia la menor idea de que existia una generalizacion en la forma de generar fractales, pues hoy aprendi que si hay una generalizacion muy interesante, me intereso mas que todo por que esta relacionado con el campo de estudio que sigo, gramaticas, compiladores y haskell.</p>
<p>Pues resulta que un L-System es una tri-tupla, (muy parecido a las gramaticas que estudiamos en automatas)</p>
<p>G (V, w, P)</p>
<p>donde:</p>
<p>V: Alfabeto o conjunto de Simbolos <br />w: Simbolo Inicial <br />P: Reglas de Produccion o de re-writing</p>
<p>Asi, esta tri-tupla es capaz de generar fractales. La forma de hacerlo es atraves de derivaciones empezando con el simbolo inicial (no olviden que para hacer una derivacion usamos las reglas de produccion). Entonces de acuerdo al fractal que queramos, podemos aplicar (derivar) varias veces.</p>
<p>Veamos un ejemplo de <a href="http://en.wikipedia.org/wiki/L-system">wikipedia</a>,</p>
<p>Example 1: Algae<br /><span style="font-family: monospace; line-height: 18px; font-size: 12px; white-space: pre;">variables : A B                 =&gt; alfabeto</span></p>
<pre><code>constants : none<br />
start  : A                      =&gt; simbolo inicial<br />
rules  : (A &rarr; AB), (B &rarr; A)      =&gt; 2 reglas de produccion<br />
which produces:<br />
n = 0 : A<br />
n = 1 : AB<br />
n = 2 : ABA<br />
n = 3 : ABAAB<br />
n = 4 : ABAABABA<br />
n = 5 : ABAABABAABAAB<br />
n = 6 : ABAABABAABAABABAABABA<br />
n = 7 : ABAABABAABAABABAABABAABAABABAABAAB<br />
</code></pre>
<p>Cuando vemos este ejemplo, no parece animar ni convencer para seguir con el proyecto, sin embargo, si vale la pena seguir cuando se ve las imagenes que se puede generar (fractales), y eso se logra con la ayuda de una libreria grafica y un sistema denominado turtle para interpretacion de strings. Si quieres convencerte al igual que yo, debes ver las imagenes de <a href="http://en.wikipedia.org/wiki/L-system">wikipedia</a>.</p>
<p>Bueno, y esta oportunidad queria compartirles la implementacion de una parte basica de este sistema L,</p>
<p>la forma en que represento un sistema L es asi:</p>
<pre><code>type L = (V, W, P)              -- Sistema L</p>
<p>type V = [String]<br />
type W = String<br />
type P = [(Char, String)]       -- simbolo -&gt; resultado == (simbolo, resultado)<br />
</code></pre>
<p>genero un parser de acuerdo a las producciones:</p>
<pre><code>--genParser :: [(Char, String)] -&gt; Parser ? ?<br />
genParser lst = if null lst<br />
                then usererror "GenParser: the argument my not be empty list."<br />
                else foldr1 (&lt;|&gt;) (map fun lst)<br />
    where fun (val, res) = (res &lt;$ pSym val)<br />
</code></pre>
<p>y genero las iteraciones enviandole el sistema L y un N que indica el numero de iteraciones, esta funcion imprime el resultado en la pantalla.</p>
<pre><code>generate :: L -&gt; Int -&gt; IO ()<br />
</code></pre>
<p>Veamos algunos ejemplos de sistemas L:</p>
<pre><code>{-<br />
Example 1: Algae</p>
<p>variables : A B<br />
constants : none<br />
start  : A<br />
rules  : (A &rarr; AB), (B &rarr; A)<br />
-}</p>
<p>algae = (["A", "B"], "A", [('A', "AB"),('B',"A")])</p>
<p>{-<br />
Example 2: Fibonacci numbers</p>
<p>variables : A B<br />
constants : none<br />
start  : A<br />
rules  : (A &rarr; B), (B &rarr; AB)<br />
-}</p>
<p>fib = (["A","B"], "A", [('A', "B"),('B',"AB")])</p>
<p>{-<br />
Example 3: Cantor dust</p>
<p>variables : A B<br />
constants : none<br />
start  : A<br />
rules  : (A &rarr; ABA), (B &rarr; BBB)<br />
-}</p>
<p>cantor1 = (["A","B"], "A", [('A', "ABA"),('B',"BBB")])<br />
cantor2 = (["-"," "], "-", [('-', "- -"),(' ',"   ")])<br />
</code></pre>
<p>Ahora mostremos algunos ejemplos:</p>
<p>*Parser&gt; generate fib 7 <br />BABABBABABBABBABABBAB</p>
<p>*Parser&gt;&nbsp;generate algae 7 <br />ABAABABAABAABABAABABAABAABABAABAAB</p>
<p>*Parser&gt; generate cantor1 4 ABABBBABABBBBBBBBBABABBBABABBBBBBBBBBBBBBBBBBBBBBBBBBBABABBBABABBBBBBBBBABABBBABA</p>
<p>*Parser&gt; generate cantor2 4 <br />- - - - - - - - - - - - - - - -<br />(Nota.- este utlimo no se grafico bien, pero se genera correctamente en consola)</p>
<p>Bueno eso es todo por hoy, si quieres ver el codigo y el proyecto, te invito que sigas este <a href="http://devel.comunidadhaskell.org/l-system">link</a>.</p>
</div>]]></description>
        </item>
                
        <item>
            <title><![CDATA[Phantom Types con uuagc]]></title>
            <link>http://ajayu.memi.umss.edu.bo/tati/weblog/2425.html</link>
            <guid isPermaLink="true">http://ajayu.memi.umss.edu.bo/tati/weblog/2425.html</guid>
            <pubDate>Wed, 24 Mar 2010 06:29:11 GMT</pubDate>
		<dc:subject><![CDATA[Haskell]]></dc:subject>
		<dc:subject><![CDATA[Comunidad Haskell]]></dc:subject>
		<dc:subject><![CDATA[Programacion Funcional]]></dc:subject>
            <description><![CDATA[<p><span class="blog_post_source"><a href="http://blog.comunidadhaskell.org/pg/blog/carliros/read/124/phantom-types-con-uuagc">http://blog.comunidadhaskell.org/pg/blog/carliros/read/124/phantom-types</a></span></p> <p>Despues de entender <a href="http://ajayu.memi.umss.edu.bo/tati/weblog/dsls-haskell-gadts-phantom-types"  target="_blank"  title="Phanton Types">Phantom Types</a>, me puse a ver la manera de hacerlo con AGs (Attribute Grammar), y la verdad no es cosa de otro mundo. Pero veamoslo paso a paso.</p>
<p>Un Phantom Type, es una tecnica que nos permite hacer chequeo de tipos en tiempo de compilacion manteniendo una gramatica abstracta sencilla y comprensible.</p>
<p>Veamoslo con el ejemplo de la pagina fuente, tenemos un evaluador de expresiones, el cual es reescrito usando gramatica de attributos de esta manera:</p>
<blockquote>
<p>DATA Expr<br />&nbsp;&nbsp; &nbsp;| Val Int<br />&nbsp;&nbsp; &nbsp;| Add le,lr : Expr<br />&nbsp;&nbsp; &nbsp;| LE e1, e2 : Expr<br />&nbsp;&nbsp; &nbsp;| Cond ex, iex, eex : Expr</p>
<p>DERIVING * : Show</p>
<p>ATTR Expr [ | | value : {Res}]</p>
<p>SEM Expr<br />&nbsp;&nbsp; &nbsp;| Val lhs.value &nbsp;= ResI @int<br />&nbsp;&nbsp; &nbsp;| Add lhs.value &nbsp;= case (@le.value, @lr.value) of<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (ResI x, ResI y) -&gt; ResI (x + y)<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt; error "Bad Arguments to Add"<br />&nbsp;&nbsp; &nbsp;| LE lhs.value &nbsp; = case (@e1.value, @e2.value) of<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (ResI x, ResI y) &nbsp;-&gt; ResB (x &lt;= y)<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -&gt; error "Bad Arguments to LE"<br />&nbsp;&nbsp; &nbsp;| Cond lhs.value = case (@ex.value) of<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ResB b -&gt; if b then @iex.value else @eex.value<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _ &nbsp; &nbsp; &nbsp; &nbsp;-&gt; error "Bad Arguments to Cond"</p>
<p>{<br />data Res = ResI Int&nbsp;| ResB Bool &nbsp;deriving Show</p>
<p>main :: IO()<br />main = print e1<br />&nbsp;&nbsp; &nbsp;where e1 = sem_Expr (Cond (LE (Val 3) (Val 5)) (Add (Val 1) (Val 2)) (Val 0))  t;br /&gt;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e2 = sem_Expr (Cond (Val 1) (Val 1) (Val 1))<br />}</p>
</blockquote>
<p>Para probarlo, hacemos "<em>uuagc -mdfcs AExpr.ag</em>", y luego lo cargamos con "<em>ghci AExpr.hs</em>" y lo ejecutamos con "<em>main</em>", y el resultado sera "<em>ResI 3</em>".</p>
<p>Hasta aqui, todo anda bien, pero que pasa si en el ag cambiamos "<em>e1</em>", por "<em>e2</em>" en el "<em>main</em>"?despues ejecutarlo nos da un error de "<em>Bad arguments to Cond</em>", asi como lo esperabamos. Pero que pasaria si <strong>no</strong> queremos obtener estos errores, y que si quisieramos capturar estos errores en tiempo de compilacion?, una forma comun de hacerlo seria cambiando nuestro tipo algebraico y escribiendo una gramatica abstracta que tenga expresiones booleanas, enteras y demas cosas. Pero una forma es usando la tecnica de Phantom Type, como lo mensionamos mas antes, mantenemos una gramatica sencilla y nos permite usar el chequeo de tipos de Haskell.</p>
<p>Entonces, lo reescribimos de esta manera:</p>
<blockquote>
<p>DATA Expr'<br />&nbsp;&nbsp; &nbsp;| Val Int<br />&nbsp;&nbsp; &nbsp;| Add le,lr : Expr'<br />&nbsp;&nbsp; &nbsp;| LE e1, e2 : Expr'<br />&nbsp;&nbsp; &nbsp;| Cond ex, iex, eex : Expr'</p>
<p>DERIVING * : Show</p>
<p>ATTR Expr' [ | | value : {Res}]<br />SEM Expr'<br />&nbsp;&nbsp; &nbsp;| Val lhs.value &nbsp;= ResI @int<br />&nbsp;&nbsp; &nbsp;| Add lhs.value &nbsp;= case (@le.value, @lr.value) of<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(ResI x, ResI y) -&gt; ResI (x + y)<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt; error "Bad Arguments to Add"<br />&nbsp;&nbsp; &nbsp;| LE lhs.value &nbsp; = case (@e1.value, @e2.value) of<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(ResI x, ResI y) &nbsp;-&gt; ResB (x &lt;= y)<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -&gt; error "Bad Arguments to LE"<br />&nbsp;&nbsp; &nbsp;| Cond lhs.value = case (@ex.value) of<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ResB b -&gt; if b then @iex.value else @eex.value<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp;-&gt; error "Bad Arguments to Cond"</p>
<p>{<br />data Res = ResI Int&nbsp;| ResB Bool&nbsp;&nbsp;deriving Show</p>
<p>newtype Expr a = E Expr'<br />&nbsp;&nbsp; &nbsp;deriving (Show)</p>
<p>-- wrappers<br />val :: Int -&gt; Expr Int<br />val = E . Val</p>
<p>add :: Expr Int -&gt; Expr Int -&gt; Expr Int<br />add (E x) (E y) = E $ Add x y</p>
<p>le :: Expr Int -&gt; Expr Int -&gt; Expr Bool<br />le (E x) (E y) = E $ LE x y</p>
<p>cond :: Expr Bool -&gt; Expr a -&gt; Expr a -&gt; Expr a<br />cond (E c) (E x) (E y) = E $ Cond c x y</p>
<p>eval :: Expr a -&gt; Res<br />eval (E e) = sem_Expr' e</p>
<p>main :: IO()<br />main = print e1<br />&nbsp;&nbsp; &nbsp;where e1 = eval (cond (le (val 3) (val 5)) (add (val 1) (val 2)) (val 0))<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; --e2 = eval (cond (val 1) (val 1) (val 1))<br />}</p>
</blockquote>
<p>Y ahora, ejecutamos lo mismo que la ultima ves y obtenemos el mismo resultado. Pero si cambiamos "<em>e1</em>" por "<em>e2</em>" en el "<em>main</em>", descomentamos "<em>e2</em>" e intentamos compilarlo, obtendremos un error de tipos en tiempo de compilacion, asi podremos contruir solo expresiones validas para nuestro evaluador.</p>
<p>Donde esta la tecnica de Phantom Type?, los hacemos atraves de "<em>newtype Expr a = E Expr'</em>&nbsp;", el cual crea un nuevo tipo parametrizando el tipo deseado, el cual es controlado por el type chequer de Haskell. Este nuevo tipo, tiene en su contructor de datos algo asi como un tipo fantasma (Phantom Type), esto pienso asi porque:</p>
<blockquote>
<p>-- el tipo del contructor de datos de Expr seria<br />E :: Expr' -&gt; Expr a</p>
<p>-- por ejemplo el tipo de val, es<br />val :: Int -&gt; Expr Int</p>
</blockquote>
<p>Asi el tipo de "<em>Expr a</em>" no refleja el contenido que tiene empaquetado, por eso pienso que el tipo de adentro es el fantasma.</p>
<p>Volviendo al tema, el siguiente paso despues de crear el tipo fantasma, es escribir las funciones wrapper, los cuales se encargan de contruir el "<em>Expr</em>' " que queremos. Y tambien es aqui donde detallamos el chequeo de tipos para Haskell.</p>
<p>En el AG podemos borrar los casos erroneos de los expresiones case, sin afectar los resultados. Y para una mejor presentacion y cuidado, podemos exportar junto con el modulo, solo las funciones wrappers y tipos necesarios.</p>
<p>Bueno, esta es la manera en que implemente Phantom Types con AGs. Si ves el documento fuente, te preguntaras como implemetar GADTs con AGs, pues es algo que yo aun sigo preguntandome, y la verdad no se si habra una manera de hacerlo con AGs, pero como al autor de decia, Phantom Types es una solucion elegante, relativamente sencilla y estandard de Haskell en comparacion con GADTs.</p>
<p>&nbsp;</p>]]></description>
        </item>
                
        <item>
            <title><![CDATA[Phanton Types con uuagc]]></title>
            <link>http://ajayu.memi.umss.edu.bo/tati/weblog/2422.html</link>
            <guid isPermaLink="true">http://ajayu.memi.umss.edu.bo/tati/weblog/2422.html</guid>
            <pubDate>Wed, 24 Mar 2010 06:29:11 GMT</pubDate>
		<dc:subject><![CDATA[Haskell]]></dc:subject>
		<dc:subject><![CDATA[Comunidad Haskell]]></dc:subject>
		<dc:subject><![CDATA[Programacion Funcional]]></dc:subject>
            <description><![CDATA[<p><span class="blog_post_source"><a href="http://blog.comunidadhaskell.org/pg/blog/carliros/read/124/phanton-types-con-uuagc">http://blog.comunidadhaskell.org/pg/blog/carliros/read/124/phanton-types</a></span></p> <p>Despues de entender <a href="http://ajayu.memi.umss.edu.bo/tati/weblog/dsls-haskell-gadts-phantom-types"  target="_blank"  title="Phanton Types">Phanton Types</a>, me puse a ver la manera de hacerlo con AGs (Attribute Grammar), y la verdad no es cosa de otro mundo. Pero veamoslo paso a paso.</p>
<p>Un Phanton Type, es una tecnica que nos permite hacer chequeo de tipos en tiempo de compilacion manteniendo una gramatica abstracta sencilla y comprensible.</p>
<p>Veamoslo con el ejemplo de la pagina fuente, tenemos un evaluador de expresiones, el cual es reescrito usando gramatica de attributos de esta manera:</p>
<blockquote>
<p>DATA Expr<br />&nbsp;&nbsp; &nbsp;| Val Int<br />&nbsp;&nbsp; &nbsp;| Add le,lr : Expr<br />&nbsp;&nbsp; &nbsp;| LE e1, e2 : Expr<br />&nbsp;&nbsp; &nbsp;| Cond ex, iex, eex : Expr</p>
<p>DERIVING * : Show</p>
<p>ATTR Expr [ | | value : {Res}]</p>
<p>SEM Expr<br />&nbsp;&nbsp; &nbsp;| Val lhs.value &nbsp;= ResI @int<br />&nbsp;&nbsp; &nbsp;| Add lhs.value &nbsp;= case (@le.value, @lr.value) of<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (ResI x, ResI y) -&gt; ResI (x + y)<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt; error "Bad Arguments to Add"<br />&nbsp;&nbsp; &nbsp;| LE lhs.value &nbsp; = case (@e1.value, @e2.value) of<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (ResI x, ResI y) &nbsp;-&gt; ResB (x &lt;= y)<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -&gt; error "Bad Arguments to LE"<br />&nbsp;&nbsp; &nbsp;| Cond lhs.value = case (@ex.value) of<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ResB b -&gt; if b then @iex.value else @eex.value<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _ &nbsp; &nbsp; &nbsp; &nbsp;-&gt; error "Bad Arguments to Cond"</p>
<p>{<br />data Res = ResI Int&nbsp;| ResB Bool &nbsp;deriving Show</p>
<p>main :: IO()<br />main = print e1<br />&nbsp;&nbsp; &nbsp;where e1 = sem_Expr (Cond (LE (Val 3) (Val 5)) (Add (Val 1) (Val 2)) (Val 0))</p>
<p>t;br /&gt;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e2 = sem_Expr (Cond (Val 1) (Val 1) (Val 1))<br />}</p>
</blockquote>
<p>Para probarlo, hacemos "<em>uuagc -mdfcs AExpr.ag</em>", y luego lo cargamos con "<em>ghci AExpr.hs</em>" y lo ejecutamos con "<em>main</em>", y el resultado sera "<em>ResI 3</em>".</p>
<p>Hasta aqui, todo anda bien, pero que pasa si en el ag cambiamos "<em>e1</em>", por "<em>e2</em>" en el "<em>main</em>"?despues ejecutarlo nos da un error de "<em>Bad arguments to Cond</em>", asi como lo esperabamos. Pero que pasaria si <strong>no</strong> queremos obtener estos errores, y que si quisieramos capturar estos errores en tiempo de compilacion?, una forma comun de hacerlo seria cambiando nuestro tipo algebraico y escribiendo una gramatica abstracta que tenga expresiones booleanas, enteras y demas cosas. Pero una forma es usando la tecnica de Phanton Type, como lo mensionamos mas antes, mantenemos una gramatica sencilla y nos permite usar el chequeo de tipos de Haskell.</p>
<p>Entonces, lo reescribimos de esta manera:</p>
<blockquote>
<p>DATA Expr'<br />&nbsp;&nbsp; &nbsp;| Val Int<br />&nbsp;&nbsp; &nbsp;| Add le,lr : Expr'<br />&nbsp;&nbsp; &nbsp;| LE e1, e2 : Expr'<br />&nbsp;&nbsp; &nbsp;| Cond ex, iex, eex : Expr'</p>
<p>DERIVING * : Show</p>
<p>ATTR Expr' [ | | value : {Res}]<br />SEM Expr'<br />&nbsp;&nbsp; &nbsp;| Val lhs.value &nbsp;= ResI @int<br />&nbsp;&nbsp; &nbsp;| Add lhs.value &nbsp;= case (@le.value, @lr.value) of<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(ResI x, ResI y) -&gt; ResI (x + y)<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt; error "Bad Arguments to Add"<br />&nbsp;&nbsp; &nbsp;| LE lhs.value &nbsp; = case (@e1.value, @e2.value) of<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(ResI x, ResI y) &nbsp;-&gt; ResB (x &lt;= y)<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -&gt; error "Bad Arguments to LE"<br />&nbsp;&nbsp; &nbsp;| Cond lhs.value = case (@ex.value) of<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ResB b -&gt; if b then @iex.value else @eex.value<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;_ &nbsp; &nbsp; &nbsp; &nbsp;-&gt; error "Bad Arguments to Cond"</p>
<p>{<br />data Res = ResI Int&nbsp;| ResB Bool&nbsp;&nbsp;deriving Show</p>
<p>newtype Expr a = E Expr'<br />&nbsp;&nbsp; &nbsp;deriving (Show)</p>
<p>-- wrappers<br />val :: Int -&gt; Expr Int<br />val = E . Val</p>
<p>add :: Expr Int -&gt; Expr Int -&gt; Expr Int<br />add (E x) (E y) = E $ Add x y</p>
<p>le :: Expr Int -&gt; Expr Int -&gt; Expr Bool<br />le (E x) (E y) = E $ LE x y</p>
<p>cond :: Expr Bool -&gt; Expr a -&gt; Expr a -&gt; Expr a<br />cond (E c) (E x) (E y) = E $ Cond c x y</p>
<p>eval :: Expr a -&gt; Res<br />eval (E e) = sem_Expr' e</p>
<p>main :: IO()<br />main = print e1<br />&nbsp;&nbsp; &nbsp;where e1 = eval (cond (le (val 3) (val 5)) (add (val 1) (val 2)) (val 0))<br />&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; --e2 = eval (cond (val 1) (val 1) (val 1))<br />}</p>
</blockquote>
<p>Y ahora, ejecutamos lo mismo que la ultima ves y obtenemos el mismo resultado. Pero si cambiamos "<em>e1</em>" por "<em>e2</em>" en el "<em>main</em>", descomentamos "<em>e2</em>" e intentamos compilarlo, obtendremos un error de tipos en tiempo de compilacion, asi podremos contruir solo expresiones validas para nuestro evaluador.</p>
<p>Donde esta la tecnica de Phanton Type?, los hacemos atraves de "<em>newtype Expr a = E Expr'</em>&nbsp;", el cual crea un nuevo tipo parametrizando el tipo deseado, el cual es controlado por el type chequer de Haskell. Este nuevo tipo, tiene en su contructor de datos algo asi como un tipo fantasma (Phanton Type), esto pienso asi porque:</p>
<blockquote>
<p>-- el tipo del contructor de datos de Expr seria<br />E :: Expr' -&gt; Expr a</p>
<p>-- por ejemplo el tipo de val, es<br />val :: Int -&gt; Expr Int</p>
</blockquote>
<p>Asi el tipo de "<em>Expr a</em>" no refleja el contenido que tiene empaquetado, por eso pienso que el tipo de adentro es el fantasma.</p>
<p>Volviendo al tema, el siguiente paso despues de crear el tipo fantasma, es escribir las funciones wrapper, los cuales se encargan de contruir el "<em>Expr</em>' " que queremos. Y tambien es aqui donde detallamos el chequeo de tipos para Haskell.</p>
<p>En el AG podemos borrar los casos erroneos de los expresiones case, sin afectar los resultados. Y para una mejor presentacion y cuidado, podemos exportar junto con el modulo, solo las funciones wrappers y tipos necesarios.</p>
<p>Bueno, esta es la manera en que implemente Phanton Types con AGs. Si ves el documento fuente, te preguntaras como implemetar GADTs con AGs, pues es algo que yo aun sigo preguntandome, y la verdad no se si habra una manera de hacerlo con AGs, pero como al autor de decia, Phanton Types es una solucion elegante, relativamente sencilla y estandard de Haskell en comparacion con GADTs.</p>
<p>&nbsp;</p>]]></description>
        </item>
                
        <item>
            <title><![CDATA[Estructuras de Datos Funcionales vs. Imperativas]]></title>
            <link>http://ajayu.memi.umss.edu.bo/tati/weblog/2419.html</link>
            <guid isPermaLink="true">http://ajayu.memi.umss.edu.bo/tati/weblog/2419.html</guid>
            <pubDate>Tue, 09 Feb 2010 15:20:59 GMT</pubDate>
		<dc:subject><![CDATA[Haskell]]></dc:subject>
		<dc:subject><![CDATA[Comunidad Haskell]]></dc:subject>
		<dc:subject><![CDATA[Programacion Funcional]]></dc:subject>
            <description><![CDATA[<p><span class="blog_post_source"><a href="http://blog.comunidadhaskell.org/pg/blog/carliros/read/107/estructuras-de-datos-funcionales-vs-imperativas">http://blog.comunidadhaskell.org/pg/blog/carliros/read/107/estructuras-d</a></span></p> <p>En esta oportunidad quiero compartir una traduccion de una de los subtitulos del libro: Purely Functional Data Structure [Chris Okasaki], que me parecio muy buena.</p>
<p><strong>Estructuras de Datos Funcionales vs. Imperativas</strong></p>
<p>Los beneficios metodologicos de los lenguajes funcionales son bien conocidos, pero aun la mayoria de los programas son escritos en lenguajes imperativos como C. Esta aparente contradiccion es facilmente explicado por el hecho de que los lenguajes funcionales han sido historicamente mas lentos que sus mas tradicionales primos, pero esta brecha se esta reduciendo. Se han hecho impresionantes avances desde un amplio frente, desde tecnologias basicas de compiladores a analisis sofisticados y optimizaciones. Sin embargo, hay un aspecto de la programacion funcional que todo escritor de compiladores debe mitigar - el uso de&nbsp;estructuras de datos&nbsp;inapropiadas o inferiores.</p>
<p>Porque las estructuras de datos funcionales son mas dificultuosas para dise&ntilde;ar e implementar que las imperativas? Hay 2 problemas basicos. Primero, desde el punto de vista de dise&ntilde;o e implementacion de estructuras de datos eficientes, la estructura de la programacion funcional contra actualizaciones destructivas (ej. asignaciones) es una desventaja asombrosa, equivalente a confiscar los cuchillos de un chef master. Al igual que los cuchillos, las actualizaciones destructivas pueden ser da&ntilde;inas cuando son mal usadas, pero tremendamente efectivas cuando son usadas apropiadamente. Las estructuras de datos imperativas a menudo confian en la asignacion de una forma crucial, y por eso se encuentran diferentes soluciones para los programas funcionales.</p>
<p>La segunda dificultad es que se espera que las estructuras de datos funcionales sean mas flexibles que sus contrapartes imperativas. En particular, cuando actualizamos una estructura de datos imperativa, tipicamente aceptamos que la version antigua de la estructura de datos ya no estara disponible, pero cuando actualizamos una estructura de datos funcional, esperamos que la antigua y nueva version de la estructura de datos estara disponible para futuros procesamientos. Una estructura de datos que soporta multiples versiones es llamado <em>persistente [persistent]</em>, mientras que una estrutura de datos que permite solo una simple version en un tiempo es llamado <em>efimera [ephemeral]</em>. Los lenguajes de programacion funcional tienen la propiedad curiosa de que todas las estructuras de datos son auntomaticamente persistentes.&nbsp;<br />Las estructuras de datos imperativas son tipicamente efimeras, pero cuando una estructura de datos persistente es requerida, los programadores imperativos no se sorprenden si la estructura de datos persistente es mas complicada y talves incluso asintoticamente menos eficiente que una equivalente estructura de datos efimera.</p>
<p>Ademas, los teoricos han establecido limites inferiores sugeriendo que los lenguajes de programacion funcional podrian ser fundamentalmente menos eficientes que los lenguajes imperativos en algunas situaciones. En vista de todos estos puntos, las estructuras de datos funcionales se parecen algunas veces al oso que baila, de quien se dice, "lo maravilloso no es que el danza muy bien, sino de  que el danza de alguna manera!". En la practica, sin embargo, la situacion no es tan triste. Como podremos ver, es a menudo posible eleborar estructuras de datos funcionales que son asintoticamente tan eficientes como las mejores soluciones imperativas.</p>
<p>&nbsp;</p>]]></description>
        </item>
                
        <item>
            <title><![CDATA[hs-plugins!!! por fin encuentro el bueno]]></title>
            <link>http://ajayu.memi.umss.edu.bo/tati/weblog/2411.html</link>
            <guid isPermaLink="true">http://ajayu.memi.umss.edu.bo/tati/weblog/2411.html</guid>
            <pubDate>Tue, 17 Nov 2009 23:08:30 GMT</pubDate>
		<dc:subject><![CDATA[Haskell]]></dc:subject>
		<dc:subject><![CDATA[Comunidad Haskell]]></dc:subject>
		<dc:subject><![CDATA[Programacion Funcional]]></dc:subject>
            <description><![CDATA[<p><span class="blog_post_source"><a href="http://blog.comunidadhaskell.org/pg/blog/darkben/read/104/hsplugins-por-fin-encuentro-el-bueno">http://blog.comunidadhaskell.org/pg/blog/darkben/read/104/hsplugins-por-</a></span></p> <p>Eso de que pongan en diferentes lados este codigo pero en cada sitio versiones diferentes es grrrraaave!!</p>
<p>pero por fin encontre el bueno:</p>
<p><a href="http://code.haskell.org/~dons/code/hs-plugins/">http://code.haskell.org/~dons/code/hs-plugins/</a></p>
<p><a href="http://hackage.haskell.org/package/plugins">http://hackage.haskell.org/package/plugins</a></p>
<p>&nbsp;</p>]]></description>
        </item>
                
        <item>
            <title><![CDATA[Setters and Getters en Haskell]]></title>
            <link>http://ajayu.memi.umss.edu.bo/tati/weblog/2380.html</link>
            <guid isPermaLink="true">http://ajayu.memi.umss.edu.bo/tati/weblog/2380.html</guid>
            <pubDate>Thu, 06 Aug 2009 00:27:37 GMT</pubDate>
		<dc:subject><![CDATA[Haskell]]></dc:subject>
		<dc:subject><![CDATA[Comunidad Haskell]]></dc:subject>
		<dc:subject><![CDATA[Programacion Funcional]]></dc:subject>
            <description><![CDATA[<p><span class="blog_post_source"><a href="http://blog.comunidadhaskell.org/pg/blog/carliros/read/96/setters-and-getters-en-haskell">http://blog.comunidadhaskell.org/pg/blog/carliros/read/96/setters-and-ge</a></span></p> <p>En Haskell podemos tambien hacer setters y getters de una forma sencilla.</p>
<p>Tenemos este codigo:</p>
<blockquote>
<p>module Main where</p>
<p>data Persona = Persona { ci&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :: CI<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  , nombre&nbsp;&nbsp; :: Name<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  , apellido :: LastName<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  , edad&nbsp;&nbsp;&nbsp;&nbsp; :: Edad<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  } deriving Show</p>
<p>type CI&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = Int<br />type Name&nbsp;&nbsp;&nbsp;&nbsp; = String<br />type LastName = String<br />type Edad&nbsp;&nbsp;&nbsp;&nbsp; = Int</p>
<p>-- instancias<br />juan :: Persona<br />juan = Persona 14322 "juan" "block" 35</p>
<p>pepe :: Persona<br />pepe = Persona 44533 "pepe" "torrez" 15</p>
</blockquote>
<p>Entonces podemos obtener los datos de cada instancia llamando a la funcion constructora de cada elemento de Persona.</p>
<p>Ejemplo:</p>
<blockquote>
<p>*Main&gt; ci pepe</p>
</blockquote>
<p>nos retornaria el CI de 'pepe', tambien podemos usar nombre, apellido o edad.</p>
<p>Para setear un valor, podemos hacer</p>
<blockquote>
<p>*Main&gt; juan {nombre = "juanes"}<br />Persona {ci = 14322, nombre = "juanes", apellido = "block", edad = 35}</p>
</blockquote>
<p>En la parte de modificar un valor de la instancia es diferente, porque lo que en realidad hace es modificar el valor en una nueva instancia sin tocar su parametro entrante. Solo toma de est&eacute; la informacion que no se modifica. Ejemplo:</p>
<blockquote>
<p>*Main&gt; juan {edad = 0}<br />Persona {ci = 14322, nombre = "juan", apellido = "block", edad = 0}<br />*Main&gt; juan<br />Persona {ci = 14322, nombre = "juan", apellido = "block", edad = 35}</p>
</blockquote>]]></description>
        </item>
                
        <item>
            <title><![CDATA[Haskell string support]]></title>
            <link>http://ajayu.memi.umss.edu.bo/tati/weblog/2381.html</link>
            <guid isPermaLink="true">http://ajayu.memi.umss.edu.bo/tati/weblog/2381.html</guid>
            <pubDate>Wed, 05 Aug 2009 20:40:19 GMT</pubDate>
		<dc:subject><![CDATA[Haskell]]></dc:subject>
		<dc:subject><![CDATA[Comunidad Haskell]]></dc:subject>
		<dc:subject><![CDATA[Programacion Funcional]]></dc:subject>
            <description><![CDATA[<p><span class="blog_post_source"><a href="http://blog.comunidadhaskell.org/pg/blog/antonio/read/95/haskell-string-support">http://blog.comunidadhaskell.org/pg/blog/antonio/read/95/haskell-string-</a></span></p> <p>Un problema muy interesante</p>
<pre>s = "&lambda;"<br />
main = do<br />
    writeFile "test.txt" s<br />
    s2 &lt;- readFile "test.txt"<br />
    print (s == s2)</p>
</pre>
<p>Si analizamos y hacemos correr este peque&ntilde;o programa el resultado deberia ser True por logica, pero el resultado real es False.</p>
<p>Segun Christian creador del blog <a href="http://lukeplant.me.uk/blog.php"  target="_blank">Luke Plant's</a></p>
<p>El problema es con la biblioteca est&aacute;ndar Haskell - muchas de las funciones previstas por el Prelud, System.IO, System.Posix y muchos otros son completamente roto (por dise&ntilde;o).&nbsp; <a href="http://lukeplant.me.uk/blog.php?id=1107301701"  target="_blank">leer mas</a></p>
<p>Don Stewart dio la siguiente solucion para este problema</p>
<pre>    import Prelude hiding (writeFile, readFile, print)<br />
    import System.IO.UTF8</p>
<p>    s = "&lambda;"<br />
    main = do<br />
        writeFile "test.txt" s<br />
        s2 &lt;- readFile "test.txt"<br />
        print (s == s2)</p>
</pre>
<p>Si hacemos correr este ejemplo el resultado sera True.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></description>
        </item>
        
    </channel>
</rss>