<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7127368407826099674</id><updated>2011-07-08T05:35:26.800-07:00</updated><category term='Haskell'/><category term='Funcional'/><category term='Programación'/><category term='Sistemas Operativos'/><category term='Teoría de la Computación'/><category term='git'/><category term='python'/><category term='bfg'/><category term='web'/><category term='zope'/><title type='text'>Strong Typed</title><subtitle type='html'>Strong Typed esta dedicado a las ciencias de la computación y temas afines. En particular a la teoría de tipos, compiladores, lenguajes de programación y su uso cotidiano.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>38</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-9026150088438323369</id><published>2010-06-09T14:10:00.000-07:00</published><updated>2010-06-09T18:45:03.660-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>My OOP Oh! moment.</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;Inheritance as the natural control structure in OOL&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A few days ago I had my Object Oriented Programming "Oh! moment". I retook my studies of smalltalk reading Ragnar Hojland's &lt;a href="http://map1.squeakfoundation.org/package/ccbcb878-e09b-48ed-a773-5939bf8c2c3e"&gt;LDAPlayer package&lt;/a&gt;. I didn't understood its design. Its LDAP-filter category seem to have a class for each possible variation of LDAP filter. &lt;span style="font-style: italic;"&gt;A class for each variation of LDAP filter, for god's sake!&lt;/span&gt;. The same thing with the LDAP messages or the BER elements. A lot of classes were empty but for a single overloaded method. What a waste!&lt;br /&gt;&lt;br /&gt;If I hadn't found Kent Beck's &lt;a href="http://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CBMQswYwAA&amp;amp;url=http%3A%2F%2Fstephane.ducasse.free.fr%2FFreeBooks%2FBestSmalltalkPractices%2FDraft-Smalltalk%2520Best%2520Practice%2520Patterns%2520Kent%2520Beck.pdf&amp;amp;rct=j&amp;amp;q=smalltalk+best+practice+patterns&amp;amp;ei=rQkQTIbDNsL88AawktCVBQ&amp;amp;usg=AFQjCNFN_g5LrBiFNK9T8SX3g4Izr0AE-g"&gt;Smalltalk Best Practice Patterns&lt;/a&gt; I would remain in ignorance for more time. In the &lt;span style="font-style: italic;"&gt;Choosing Message Pattern&lt;/span&gt; he says:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;Procedural programs implement variations with conditional logic, either if-then-else or case statements. Two problems arise from such hard-coded logic. First, you cannot add a new variation without modifying the logic. This can be a ticklish operation, getting the new variation is without disturbing the existing variations. Second, such logic tends to propagate. You do not have to account for the variation in one place, you have to account for it in several. Adding a new variation means tickling all of the places where the logic lives.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;Messages provide a disciplined way to handle theme-and-variation programming. Because the variations live in different objects, they have much less opportunity to interfere with each other than just putting the variations in different parts of the same routine. The client, the object invoking the variations, is also isolated from what variation is currently active.&lt;/span&gt;  &lt;span style="color: rgb(0, 0, 102);"&gt;&lt;br /&gt;&lt;br /&gt;Adding a new variation is as simple as adding a new object that provides the same set of messages the other variations provide and introducing it to the object that wants to invoke the variations.&lt;/span&gt;&lt;/blockquote&gt;If you are choosing between several action according to the parameter's class, then you should convert those actions in a new methods in each one of the respective classes and make an unconditional invocation to the new method. In this way you remove a case statement.&lt;br /&gt;&lt;br /&gt;In the same way, if you are choosing between action according to the parameter's &lt;span style="font-style: italic;"&gt;value&lt;/span&gt;, it is an indication that you should subclass the parameter's class. In this way, an LDAPFilterSingle becomes LDAPFilterWIthNot, LDAPFilterWithAnd and so many others.&lt;br /&gt;&lt;br /&gt;The problem with OO teaching is that it makes emphasis in subclases as subtypes and the &lt;a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle"&gt;Liskov substitution principle&lt;/a&gt;. With this point of view, your most important work as a designer is to define the correct taxonomy of your objects, and that's one of the most difficult problems that exists. If you are forced to classify all the future types of your system today, &lt;a href="http://okmij.org/ftp/Computation/Subtyping/"&gt;you're screwed&lt;/a&gt;. Subclasses as subtypes is not the way inheritance was intended to be used. You make a subclass  to share common code. You make a subclass to overload a method, so you can avoid an &lt;span style="font-style: italic;"&gt;if..then&lt;/span&gt; or a &lt;span style="font-style: italic;"&gt;case&lt;/span&gt;. A subclass is not an ontologic statement about the nature of the instances.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Open Classes goodies&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So, subclassing and overloading allows you to reduce the control structures in your methods. But the goodies don't end there. Since in smalltalk all the classes are open (you can add your own methods), this pattern is valid even for classes outside your project. So, the base classes of the system become more powerful with the time.&lt;br /&gt;&lt;br /&gt;That's being in another league regards flexibility.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Side note:&lt;/span&gt; Ruby has open classes too. As a python programmer I've always seen Ruby as a language too similar to python to be worth to learn it. Now, I feel a little Ruby envy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-9026150088438323369?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/9026150088438323369/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=9026150088438323369' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/9026150088438323369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/9026150088438323369'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2010/06/my-oop-oh-moment.html' title='My OOP Oh! moment.'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-8719515688223498635</id><published>2010-01-29T17:14:00.000-08:00</published><updated>2010-02-03T11:09:59.995-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Funcional'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>Language's culture</title><content type='html'>I don't remember how I get interested in Haskell, but I remember that &lt;a href="http://www.haskell.org/haskellwiki/Why_Haskell_matters"&gt;Why Haskell matters&lt;/a&gt; sealed the deal. There was a comparison of  QuickSort implementations in C++ and Haskell. The Haskell version was so beautiful, so concise, that I had to learn it.&lt;br /&gt;&lt;br /&gt;Even the first time I saw the comparison,  I knew that it wasn't all fair. The algorithms weren't the same. The C++ version sorted an array in place. The Haskell acted upon lists. Of course, you can write a Haskell version that use mutable arrays. And you can, with some modification, implement the C++ version using lists, list concatenation and filter.&lt;br /&gt;&lt;br /&gt;But why a C++ programmer would use a list structure when an array can do the work? Why a programmer would spend his time learning Haskell to then solve a problem imperatively?&lt;br /&gt;&lt;br /&gt;Each language impose a culture, not only by forbidding thing, but by making other easy. Haskell not only gives you functions as firt-class citizens, but it makes so easy to compose, curry and uncurry them, that it is only natural to do it.&lt;br /&gt;&lt;br /&gt;This composability is the real reason why to program in Haskell is a pleasure.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-8719515688223498635?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/8719515688223498635/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=8719515688223498635' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/8719515688223498635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/8719515688223498635'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2010/01/languages-culture.html' title='Language&apos;s culture'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-2262042225526950443</id><published>2010-01-28T16:33:00.000-08:00</published><updated>2010-02-01T10:54:46.654-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Desarrollando con zc.buildout</title><content type='html'>En un post &lt;a href="http://strongtyped.blogspot.com/2010/01/zcbuildout.html"&gt;anterior&lt;/a&gt; comentaba que es zc.buildout, por qué puede necesitarlo un desarrollador y como instalarlo. Ahora hablaré sobre como desarrollar un proyecto usandolo.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;buildout.cfg&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;buildout.cfg es el archivo que determina como se construirá el proyecto, cuales son sus partes y como generarlas. El formato del archivo es el tradicional .INI de windows, dividido en &lt;span style="font-style: italic;"&gt;secciones&lt;/span&gt; (nombres encerrados entre corchetes) formadas por lineas con el formato &lt;span style="font-style: italic;"&gt;clave=valor&lt;/span&gt;.&lt;br /&gt;&lt;blockquote style="color: rgb(0, 0, 102); font-family: courier new;"&gt;&lt;pre class="literal-block"&gt;[buildout]&lt;br /&gt;develop = .&lt;br /&gt;parts = dependencias&lt;br /&gt;&lt;br /&gt;[dependencias]&lt;br /&gt;recipe = zc.recipe.egg:eggs&lt;br /&gt;eggs = python-ldap&lt;br /&gt;      docutils&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;La sección &lt;span style="font-family: courier new; color: rgb(0, 0, 102);"&gt;buildout&lt;/span&gt; es la única requerida en el archivo buildout.cfg. La primera linea&lt;br /&gt;&lt;blockquote style="font-family: courier new; color: rgb(0, 0, 102);"&gt;&lt;span style="font-size:85%;"&gt;develop = .&lt;/span&gt;&lt;/blockquote&gt;indica cuales son los directorios con los paquetes de desarrollo (los paquetes o &lt;span style="font-style: italic;"&gt;huevos&lt;/span&gt; en los que estamos trabajando y que todavía no hemos instalado). Cada uno de esos directorios debe tener un archivo &lt;span style="font-style: italic;"&gt;setup.py&lt;/span&gt; que defina el &lt;span style="font-style: italic;"&gt;huevo&lt;/span&gt; de python.&lt;br /&gt;&lt;blockquote style="font-family: courier new; color: rgb(0, 0, 102);"&gt;&lt;span style="font-size:85%;"&gt;parts = dependencias&lt;/span&gt;&lt;/blockquote&gt;dice que este proyecto esta formado por una única &lt;span style="font-style: italic;"&gt;parte&lt;/span&gt;, llamada &lt;span style="font-style: italic;"&gt;"dependencias"&lt;/span&gt;. Cada parte deberá tener su propia sección donde se indique como &lt;span style="font-style: italic;"&gt;construirla&lt;/span&gt;. En nuestro ejemplo&lt;br /&gt;&lt;blockquote style="font-family: courier new; color: rgb(0, 0, 102);"&gt;&lt;span style="font-size:85%;"&gt;[buildout]&lt;br /&gt;develop = .&lt;br /&gt;parts = dependencias&lt;br /&gt;&lt;br /&gt;[dependencias]&lt;br /&gt;recipe = zc.recipe.egg:eggs&lt;br /&gt;eggs = python-ldap&lt;br /&gt;                  docutils&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;span style="font-style: italic;"&gt;zc.recipe.egg&lt;/span&gt; es un paquete que define un &lt;span style="font-style: italic;"&gt;récipe &lt;/span&gt;con nombre&lt;span style="font-style: italic;"&gt; eggs &lt;/span&gt;. Este recipe es un programa encargado de construir la parte &lt;span style="font-style: italic;"&gt;dependencias&lt;/span&gt;. Lo que hace este recipe en particular es descargar los paquetes &lt;span style="font-style: italic;"&gt;python-ldap&lt;/span&gt; y &lt;span style="font-style: italic;"&gt;docutils&lt;/span&gt;. Nota que una linea que comienza con espacios significa que es la continuación de la linea anterior.&lt;br /&gt;&lt;br /&gt;Así como hay récipes para instalar los paquetes o huevos de python, hay otros que instalan aplicaciones en C, como openldap o postgresql o para descargar proyectos vía CVS o git. El &lt;span style="font-style: italic;"&gt;python package index&lt;/span&gt; tiene una &lt;a href="http://pypi.python.org/pypi?%3Aaction=search&amp;amp;term=zc.buildout&amp;amp;submit=search"&gt;larga lista&lt;/a&gt; de paquetes con récipes para zc.buildout.&lt;br /&gt;&lt;br /&gt;Cuando hayas terminado con &lt;span style="font-family: courier new;"&gt;buildout.cfg&lt;/span&gt; puedes construir todas las dependencias de tu sistema con un simple comando:&lt;br /&gt;&lt;blockquote style="font-family: courier new; color: rgb(0, 0, 102);"&gt;&lt;span style="font-size:85%;"&gt;{ ubicado en la raiz de tu proyecto}&lt;br /&gt;$ bin/buildout&lt;/span&gt;&lt;/blockquote&gt;Deberas ejecutar buildout cada vez que agregues una nueva dependencia y hayas editado buildout.cfg. Pero lo más importante es que tus usuarios también podrán instalar todas las dependencias de tu aplicación ejecutando buildout.&lt;br /&gt;&lt;br /&gt;Esto es todo lo que hay que saber de zc.buildout para usarlo en tus desarrollos. El resto es buscar las recetas que generen las partes que necesites. En última instancia, un récipe es simplemente un script en python, por lo que puedes crear uno nuevo si no consigues ninguno que satisfaga tus necesidades.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-2262042225526950443?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/2262042225526950443/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=2262042225526950443' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/2262042225526950443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/2262042225526950443'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2010/01/desarrollando-con-zcbuildout.html' title='Desarrollando con zc.buildout'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-6620945307379916432</id><published>2010-01-22T04:03:00.000-08:00</published><updated>2010-02-13T12:18:04.437-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><category scheme='http://www.blogger.com/atom/ns#' term='Funcional'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>A monad non-tutorial</title><content type='html'>&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;...or why you shouldn't ask what a monad is&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"What is a monad?" is one of the most common question when you're learning Haskell. And it's there when troubles start, because it is the wrong question. Ask a wrong question, and you'll get the wrong answer. The only right answer to this question is a &lt;a href="http://homepages.inf.ed.ac.uk/wadler/papers/essence/essence.ps"&gt;mathematic definition&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;[...] A monad is a triple (M, unitM, bindM) consisting in a type constructor M and a pair of polymorphic functions {unitM :: a -&gt; M a} and {bindM :: M a -&gt; (a -&gt; M b)  -&gt; M b}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;These functions must satisfy three laws [...]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;(unitM a) `bindM` k = k a&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;m `bindM` unitM = m&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;m `bindM` (\a -&gt; (k a) `bindM` (\b -&gt; h b)) =&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;      (m `bindM` \a -&gt; (k a)) `bindM` (\b -&gt; h b)&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;After a reverential minute of silence, you start to figure it out that maybe you shouldn't be asking that. Your mind is working fast to come out with a phrase to fool your interlocutor into thinking that you have understood. But there's nothing to understand.&lt;br /&gt;&lt;br /&gt;You'll see, that's the way definitions work. They are use to label objects, that's the only thing they are good for. So if the definition of homo sapiens is "an animal, mammal, of the order of primates, family hominidae and genus homo" and if you know what is an animal, a mammal, a primate... etc. then you can put objects into classes: "my friend Ed, homo sapiens; mi dog Buch, no".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;It is why, not what&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The least interesting thing about monads is its definition. The real question is "why?". You only make a definition if it is useful, if you use it frequently. So, let's see how this definition is implemented in Haskell:&lt;br /&gt;&lt;blockquote  style="color: rgb(0, 0, 102);font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;class Monad m where&lt;br /&gt;   (&gt;&gt;=) :: m a -&gt; (a -&gt; m b) -&gt; m b&lt;br /&gt;   return a :: m a&lt;/span&gt;&lt;/blockquote&gt;So, a monad is an Haskell class. Or, if you are a Java guy (and let's confess it, who isn't?), then you can think in a monad as an interface. But, again, why? When you see FileishInterface with its methods open, close, read, write and seek, you say: "Oh, so FileishInterface represents objects that behave like a file, I get it". You can think in a FileishInterface instance using a TCP connection or a byte array.  With monads, there is nothing in its interface that make you think in a concrete example.&lt;br /&gt;&lt;br /&gt;An that is a good thing. After all, FileishInterface is so concrete that it could be used only in a very few cases. The interface of Monad is so generic that it could be used in a wide range of objects. Paradoxically, that make it hard to think in a use when you are learning the concept.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;When&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The other problem when you are learning monad is that you want to use them. You open your editor and say "I'll make a program and I'm gonna create my own monads and I'll show it in the Haskell Café and I'll become a member of the &lt;span style="font-style: italic;"&gt;Secret Category Cabal&lt;/span&gt; and I'm gonna spend my evenings talking about Kleili arrows and functors and maybe Paul Hudak will friend me in facebook". Curiously, you have never say "Mmm, today I feel like I'm gonna make a program that uses hashtables". You don't try to impose data structures to your imperative programming, so why are you trying to force monads in your haskell programs? Don't go after monads, let the monads find you.&lt;br /&gt;&lt;br /&gt;You'll know when you need them. One day you will make a program and you'll write a type constructor:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 102);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;type M a = ....&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;(did you notice how your type constructor's name is "M" as in "Monad"? This is a clever, subtle way in which the author -- me -- hints that you've started to write a monad).&lt;br /&gt;&lt;br /&gt;If you use your type constructor M to create only one type, say &lt;span style="font-style: italic;"&gt;M Integer&lt;/span&gt;, then you don't need monads. But, after a few hours of programming, types start to appear and you have &lt;span style="font-style: italic;"&gt;M Char&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;M String&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;M Bool&lt;/span&gt; and others. After a few coups of coffee you have functions all over the place with types like &lt;span style="font-style: italic;"&gt;Integer -&gt; M Integer&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;Integer -&gt; M Bool&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;Bool -&gt; M Char&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Then you need to chain these function together, but it's a pain in the functional ass. Each time you need to connect two functions, say &lt;span style="font-style: italic;"&gt;Integer -&gt; M Bool&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;Bool -&gt; M Char&lt;/span&gt;, you need to invoke the first function, extract the value inside M and invoke the second one. And it is then --I hope-- that the "aha! moment" comes to you. You can write a function that extract the &lt;span style="font-style: italic;"&gt;a&lt;/span&gt; from &lt;span style="font-style: italic;"&gt;M a&lt;/span&gt; and use it to invoke  a  function with type &lt;span style="font-style: italic;"&gt;a -&gt; M b&lt;/span&gt;.&lt;span style="font-style: italic;"&gt; &lt;/span&gt;You have invented &lt;span style="font-style: italic;"&gt;&lt;span style="font-style: italic;"&gt;&gt;&gt;=&lt;/span&gt;&lt;/span&gt;, the&lt;span style="font-style: italic;"&gt; &lt;/span&gt;bind function!&lt;br /&gt;&lt;br /&gt;Since you wrote the type constructor M, you are the one who know how to extract &lt;span style="font-style: italic;"&gt;a&lt;/span&gt; from &lt;span style="font-style: italic;"&gt;M a&lt;/span&gt;. And you know how to chain that value to &lt;span style="font-style: italic;"&gt;a -&gt; M b&lt;/span&gt;. Each monad has its own definition of &gt;&gt;=, adapted to its structure.&lt;br /&gt;&lt;br /&gt;When is &lt;span style="font-style: italic;"&gt;return&lt;/span&gt; used? If you see the &gt;&gt;= definition, it needs a&lt;span style="font-style: italic;"&gt; M a&lt;/span&gt; to start. If you have a value of type &lt;span style="font-style: italic;"&gt;a&lt;/span&gt; instead, you'll need a way to transform it into &lt;span style="font-style: italic;"&gt;M a&lt;/span&gt;. That's what &lt;span style="font-style: italic;"&gt;return&lt;/span&gt; does.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Now what?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hopefully you know by now  that the definition of monads is not the important part for a programmer. You only need to focus in the type constructor and the bind function. What does the type constructor represent? What is it used for? How they defined bind: how it extract the value inside one of those new types and how it chain it to the &lt;span style="font-style: italic;"&gt;a -&gt; m b&lt;/span&gt; function?&lt;br /&gt;&lt;br /&gt;So, now you can go back to those tutorials that explain what are monads and give them a second look. You can review the do notation that help you to write your long chain of  &gt;&gt;= expression in a clear way. Good luck.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;The IO Monad&lt;/span&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;But wait! I can't end this post without talking about IO monads, can I? A monad is a monad is a monad. IO monads are not the exception. Since your understanding of monad is better now and my hands are tired, I'll cheat a little.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-style: italic;"&gt;IO a&lt;/span&gt; data constructor can be seen as a function that takes a value of type &lt;span style="font-style: italic;"&gt;a&lt;/span&gt; and returns a C program. When that program is compiled and executed, it will return that value. That's the work of the IO bind. It compiles and executes the first argument (&lt;span style="font-style: italic;"&gt;IO a&lt;/span&gt;), gets the &lt;span style="font-style: italic;"&gt;a&lt;/span&gt; values and feed it to its second argument (&lt;span style="font-style: italic;"&gt;a -&gt; IO b&lt;/span&gt;) which returns a new C program that will return a value of type b. That's why the haskellers can see you right into the eyes and say that Haskell is a pure language: "Of course that putChar is a pure function. Giving the same input, it will always return the same C program!".&lt;br /&gt;&lt;br /&gt;Thinking in this way is useful to understand why IO is a monad, but it is a waste of your attention. In your daily programming, you'll be better thinking that the IO values are an imperative language embedded in haskell and &gt;&gt;= is its interpreter.&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-6620945307379916432?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/6620945307379916432/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=6620945307379916432' title='6 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/6620945307379916432'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/6620945307379916432'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2010/01/monad-non-tutorial.html' title='A monad non-tutorial'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-4255647653012788160</id><published>2010-01-21T11:30:00.000-08:00</published><updated>2010-01-21T14:04:32.249-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>zc.buildout</title><content type='html'>Comienzo hoy  una serie de artículos sobre desarrollo de aplicaciones en python, particularmente, desarrollo web. Y nuestro invitado del día es &lt;span style="font-weight: bold;"&gt;zc.buildout&lt;/span&gt;. O simplemente buildout, para los amigos.&lt;br /&gt;&lt;br /&gt;A buildout lo había mencionado de pasada en otras oportunidades. Ahora es el momento de tratarlo con exclusividad, como se merece.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Que problema soluciona buildout?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Desarrollar una aplicación para distribuirla tiene una serie particular de problemas. Los equipos donde se instale pueden no tener todas las aplicaciones de las que esta depende. O pueden tener versiones viejas o incompatibles. Este problemas se agrava cuando desarrollamos en un lenguaje de scripts. Aquí las dependencias suelen ser librerías desarrolladas con ese mismo lenguaje. Tristemente, ninguna distribución puede ofrecer una versión actualizada de todos los proyectos hechos en python, perl o ruby.&lt;br /&gt;&lt;br /&gt;Esta situación le deja al programador (es decir a ti) la necesidad de hacer que el instalador de su aplicación busque e instale todas las dependencias, en sus versiones correctas. Esto distrae al programador de su tarea real: desarrollar la mejor aplicación posible.&lt;br /&gt;&lt;br /&gt;Y precisamente este es el trabajo de buildout: asegurarse de conseguir e instalar todas las piezas de software que tu aplicación necesita.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Como funciona&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Buildout se encarga de ensamblar todas las partes que necesita tu aplicación. Esto lo logra esto a traves de un lenguaje declarativo y extensible. Una serie de "recetas" pre-establecidas resuelven los problemas típicos del manejo de dependencias. Así que en la mayoría de los casos basta con indicarle tus necesidades y buildout se encargará en resolverlas.&lt;br /&gt;&lt;br /&gt;La parte extensible entra en juego cuando tu aplicación necesita algo inusual. Entonces programas una nueva receta (en python) que resuelva esa dependencia y listo. El mundo tiene una nueva receta de buildout que puede ser usada por otros desarrolladores y cada día el trabajo con buildout se facilita.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Ejemplo práctico&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;El primer paso es, desde luego instalar buildout:&lt;br /&gt;&lt;blockquote  style="color: rgb(0, 0, 102);font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;$ sudo easy_install zc-buildout&lt;/span&gt;&lt;/blockquote&gt;En &lt;a href="http://strongtyped.blogspot.com/2008/02/instalando-zope-3.html"&gt;otro post&lt;/a&gt; comenté como instalar easy_install. Buildout depende exclusivamente de easy_install y es todo lo que el desarrollador necesita para manejar el problema de las dependencias. Sin embargo, el usuario final podría no tener instalado zc-buildout, por lo cual el recomendable agregar a tu proyecto un pequeño script que se encargue de conseguirlo:&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;&lt;span style="color: rgb(0, 0, 102);"&gt;# Bajamos bootstrap&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;$ wget 'http://svn.zope.org/*checkout*/buildout-website/trunk/bootstrap.py&lt;/span&gt;'&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;# Y lo guardamos en un lugar seguro para&lt;br /&gt;#agregarlo&lt;/span&gt; &lt;span style="color: rgb(0, 0, 102);"&gt;a cada poyecto que use buildout&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;$ mv bootstrap.py ~/bin&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;Ok, ya tenemos instalado buildout y bootstrap, ahora solo necesitamos un proyecto en python:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 102);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;# Creamos nuestro nuevo proyecto&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;$ mkdir miproyecto&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;$ cd miproyecto&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# Inicializamos buildout&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;$ buildout init&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;# ...y copiamos bootstap.py para&lt;br /&gt;# beneficio de nuestros usuarios&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;$ cp ~/bin/bootstrap.py .&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;Esto creará los siguientes objetos en nuestro directorio:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 102);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;bin/&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;develop-eggs/  &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;eggs/  &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;parts/&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="color: rgb(0, 0, 102);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;buildout.cfg&lt;/span&gt;&lt;/span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;En &lt;span style="font-weight: bold;"&gt;bin/&lt;/span&gt; esta una copia de buildout. Aquí se instalarán los comandos de todos los huevos (paquetes en python) que instalemos.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;develop-eggs/&lt;/span&gt; es un directorio manejado por buildout y que no necesitamos tocar directamente. Aquí habrá un enlace simbólico a cada &lt;span style="font-style: italic;"&gt;paquete en desarrollo&lt;/span&gt; que necesitemos. Un paquete en desarrollo es, como su nombre lo indica, un paquete sobre el cual estamos trabajando todavía. Los paquetes en desarrollo no están instalados en el sistema y normalmente son inaccesibles a otros paquetes. Es por eso que buildout les ha dedicado todo un directorio: para poder acceder a ellos sin necesidad de instalarlos.&lt;br /&gt;&lt;br /&gt;En &lt;span style="font-weight: bold;"&gt;eggs/&lt;/span&gt; irán todos los paquetes o huevos de los que nuestra aplicación necesite. De nuevo, buildout los bajará por nosotros y verificará en cada ocasión, de ser necesario, que estén en su última versión.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;parts/&lt;/span&gt; es usado por los récipes. Aquí es donde se compilará, por ejemplo, una aplicación en C, que necesite nuestra aplicación.&lt;br /&gt;&lt;br /&gt;Cuando empaquetemos nuestra aplicación, el programa empaquetador de python (setuptools) creará otros directorios, no relacionados con buildout.&lt;br /&gt;&lt;br /&gt;Finalmente, está el archivo &lt;span style="font-weight: bold;"&gt;buildout.cfg&lt;/span&gt;. Para nosotros como desarrolladores, este es el corazón de buildout. Aquí indicaremos todas las instrucciones necesarias para que nuestra aplicación encuentre un entorno donde pueda correr sin problemas. Indicaremos cuales librerías en python necesita, y si estas son estables o no. Le diremos que aplicaciones en C, C++ u otro lenguaje tendrá que descargar, compilar e instalar, si ese fuera el caso. Le diremos si necesitamos crear una base de datos y cual debe ser su contenido. En fin, buildout.cfg nos dice todo lo que necesitamos saber de las dependencias de nuestra aplicación.&lt;br /&gt;&lt;br /&gt;El contenido de buildout.cfg lo trataré en la próxima entrega.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-4255647653012788160?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/4255647653012788160/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=4255647653012788160' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/4255647653012788160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/4255647653012788160'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2010/01/zcbuildout.html' title='zc.buildout'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-2158287230010499843</id><published>2010-01-20T07:16:00.000-08:00</published><updated>2010-01-20T07:41:07.149-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>Por qué git</title><content type='html'>Lo confieso: como desarrollador solitario, nunca había sido amigo del control de versiones. Como serlo, si requería tener corriendo un servicio, con las configuraciones y reconfiguraciones que ello conlleva (por mi manía de siempre probar la última distro)? Jamás me sentí a gusto con CVS, sin poder saber a ciencia cierta por qué.&lt;br /&gt;&lt;br /&gt;Hasta que conocí git. Primero que nada, git es una aplicación. No requiere tener un servidor corriendo. Tu repositorio esta en el mismo directorio que tu proyecto, por lo que el respaldo es mas sencillo. Solo tipeas los comandos y ya!&lt;br /&gt;&lt;br /&gt;En segundo lugar, es &lt;span style="font-style: italic;"&gt;distribuido&lt;/span&gt;. Trabajo al menos en un par de computadores, sin contar una que otra laptop que uso de vez en vez contra mi voluntad. Puedo tener en cada equipo mi proyecto con toda su historia, trabajar independientemente y luego sincronizar con los demás. Cada PC es un equipo de desarrollo tan igual como los demás.&lt;br /&gt;&lt;br /&gt;En tercer lugar, puedo elegir la estructura de mis repositorios, como se organizan jerarquicamente. En mi ciclo de trabajo personal elegí no tener un repositorio central, pero en el trabajo, donde más de una persona puede hacer cambios en un proyecto, usamos un maestro.&lt;br /&gt;&lt;br /&gt;Pero la característica matadora de git son definitivamente sus branches. Hacer una rama de un proyecto es tan natural, tan barata, que forma parte integral de la forma de desarrollo en git. No puedo resaltar suficientemente este hecho: git me ha hecho un mejor usuario de los sistemas de versiones.&lt;br /&gt;&lt;br /&gt;Como es esto? Dado que en mis experiencias previas, ramificar el proyecto era doloroso, tenía una única rama, donde aplicaba todos los cambios. Si trabajaba en tres aspectos distintos de una aplicación, todos los cambios iban al directorio de trabajo. De esta manera, los commits contenían cambios no relacionados. Hacer un commit era básicamente, hacer un respaldo del proyecto.&lt;br /&gt;&lt;br /&gt;Fue usando las ramas de git que obtuve la iluminación: un aspecto, una rama. Aspecto culminado, commit. Apareció un bug que debo atender? Pues creo una nueva rama, corrijo el bug, pruebo y hago el commit y merge o rebase. Regreso a la rama  inicial y sigo trabajando con el aspecto original.&lt;br /&gt;&lt;br /&gt;Cada commit debe ser un &lt;span style="font-style: italic;"&gt;milestone&lt;/span&gt;, un &lt;span style="font-style: italic;"&gt;hito&lt;/span&gt; significativo en el desarrollo del programa "Agregue la caracteristica X", "Corregí el bug Y", "Cambié el algoritmo Z". Y no como antes "Toqué los archivos A, B, C, D y E  porque estoy trabajando en X, Y y Z", repetido día tras día..&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-2158287230010499843?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/2158287230010499843/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=2158287230010499843' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/2158287230010499843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/2158287230010499843'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2010/01/por-que-git.html' title='Por qué git'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-4035919255169753892</id><published>2010-01-18T12:03:00.000-08:00</published><updated>2010-01-18T12:36:44.505-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bfg'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='zope'/><title type='text'>Ya salió el libro de repoze.bfg</title><content type='html'>Ya salió el &lt;a href="http://plope.com/static/bfg-1.2b1dev.pdf"&gt;libro&lt;/a&gt; de&lt;a href="http://bfg.repoze.org/"&gt; repoze.bfg&lt;/a&gt;,  el interesante entorno de desarrollo en python+WSGI. repoze.bfg es un framework minimalista inspirado en zope. Comparativamente ofrece las siguientes ventajas:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Fácil de entender: Al ser un framework pequeño, puede ser entendido con menor esfuerzo.&lt;/li&gt;&lt;li&gt;Familiaridad: Si ya has programado en zope, repoze.bfg es el paraíso: es zope2 bien hecho.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Usa WSGI: Lo cual le permite interoperar más fácilmente con otras aplicaciones (aunque la última versión de zope parece que vendrá por defecto para usar WSGI).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Pagas solo por lo que comes: Viene sin soporte para base de datos, autenticación, autorización o manejo de sesión. Toda esta funcionalidad esta soportada por proyectos independientes.&lt;/li&gt;&lt;li&gt;Rápido: Dado que las aplicaciones desarrolladas en bfg no contienen componentes innecesarios, su velocidad de respuesta aumenta.&lt;/li&gt;&lt;/ul&gt;Desde luego, bfg también tiene sus inconvenientes respecto a zope. Y como suele suceder, algunas de sus características positivas tienen su lado negativo:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No TTW: Zope2 ganó una inmensa popularidad al permitir el desarrollo de aplicaciones a través del web. bfg es un framework para programadores exclusivamente.&lt;/li&gt;&lt;li&gt;Pocos componentes integrados: Fiel a su idea original de minimalismo, es responsabilidad del programador decidir sobre los componentes básicos de su aplicación. Cada vez. Por cada componente. Incluso en las pruebas más triviales.&lt;/li&gt;&lt;/ul&gt;En definitiva, repoze.bfg dará que hablar. Este framework tiene el potencial para desarrollar el sucesor de Plone.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-4035919255169753892?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/4035919255169753892/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=4035919255169753892' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/4035919255169753892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/4035919255169753892'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2010/01/ya-salio-el-libro-de-repozebfg.html' title='Ya salió el libro de repoze.bfg'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-7300525917084550709</id><published>2010-01-18T06:18:00.000-08:00</published><updated>2010-01-18T07:08:34.943-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Funcional'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>Más diversión con tipos algebraicos</title><content type='html'>En &lt;a href="http://strongtyped.blogspot.com/2010/01/diversion-con-tipos-de-datos.html"&gt;otra entrada&lt;/a&gt; comenté la elegancia de los tipos de datos algebraicos (ADT) y como este simple concepto reemplaza a las enumeraciones, estructuras y uniones de otros lenguajes. Adicionalmente, los ADT ofrecen otra característica interesante: el emparejamiento de patrones (&lt;span style="font-weight: bold;"&gt;pattern matching&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;En principio, los elementos de un ADT solo pueden ser accedidos por medio del emparejamiento de patrones. Veamos un ejemplo con un tipo de datos lista:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;&lt;span style="font-family: courier new;"&gt;data Lista a = Nulo | Cons a  (Lista a)&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;lista1 = Nulo&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;lista2 = Cons 3 Nulo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;lista3 = Cons 7.3 (Cons 4.0 Nulo)&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;Nota como el tipo de datos Lista es polimórfica (define listas de enteros, reales o cualquier otro tipo) y recursiva (una lista de tipo &lt;span style="font-style: italic;"&gt;a&lt;/span&gt; esta formada por un valor de tipo &lt;span style="font-style: italic;"&gt;a&lt;/span&gt; unida a una lista de tipo &lt;span style="font-style: italic;"&gt;a&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;Los valores de tipo Lista están compuestos, o bien por el valor &lt;span style="font-weight: bold;"&gt;Nulo&lt;/span&gt;, o bien por un par ordenado "marcado" por &lt;span style="font-weight: bold;"&gt;Cons&lt;/span&gt;, cuyo primer elemento es de tipo &lt;span style="font-style: italic;"&gt;a&lt;/span&gt; y su segundo es de tipo &lt;span style="font-style: italic;"&gt;Lista a&lt;/span&gt;. Estos dos "marcadores" forman la base para el emparejamiento de patrones. Por ejemplo, para calcular la longitud de una lista:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family: courier new;"&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;longitud Nulo = 0&lt;br /&gt;longitud Cons a b = 1 + longitud b&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;Estas dos lineas combinadas, forman la definición de la función &lt;span style="font-style: italic;"&gt;longitud&lt;/span&gt;. Utilizamos la primera solamente cuando se invoca &lt;span style="font-style: italic;"&gt;longitud&lt;/span&gt; con la lista vacia (valor &lt;span style="font-style: italic;"&gt;Nulo&lt;/span&gt;) y la segunda en los otros casos (valor &lt;span style="font-style: italic;"&gt;Cons&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;Una ventaja del emparejamiento de patrones, es que podemos ver con claridad cuando nuestras funciones manejan todos los casos posibles. El compilador puede advertirnos cuando obviemos alguno.&lt;br /&gt;&lt;br /&gt;Adicionalmente, como dividimos nuestra función &lt;span style="font-style: italic;"&gt;longitud&lt;/span&gt; en dos expresiones, resulta más fácil de leer. Podemos concentrarnos en las peculiaridades de cada patrón por separado.&lt;br /&gt;&lt;br /&gt;Cabe destacar que el emparejamiento de patrones se puede usar también para separar casos de acuerdo a los valores dentro de los ADT, no solo por sus "marcadores". Por ejemplo, la función &lt;span style="font-style: italic;"&gt;elem&lt;/span&gt; que devuelve el i-simo elemento de una lista:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family: courier new;"&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;elem 0 (Cons a b) = a&lt;br /&gt;elem i (Cons a b) = elem (i-1) b&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;En este caso, solo aplicamos la primera expresión cuando pidamos el elemento cero de una lista.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-7300525917084550709?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/7300525917084550709/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=7300525917084550709' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/7300525917084550709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/7300525917084550709'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2010/01/mas-diversion-con-tipos-algebraicos.html' title='Más diversión con tipos algebraicos'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-2357134676322629499</id><published>2010-01-14T12:30:00.000-08:00</published><updated>2010-01-14T14:01:05.889-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Funcional'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>Diversión con tipos de datos algebraícos</title><content type='html'>Los &lt;span style="font-style: italic;"&gt;tipos de datos algebraicos&lt;/span&gt; o &lt;span style="font-weight: bold;"&gt;ADT&lt;/span&gt; (por sus siglas en inglés: Algebraic Data Types) son una de las características más interesante de los   "nuevos" lenguajes funcionales, y por nuevos quiero decir de la época de SML. Lo simpático de los ADTs es que reunen en un solo concepto lo que en otros lenguajes serían enumeraciones, estructuras y uniones.&lt;br /&gt;&lt;br /&gt;Por ejemplo, las enumeraciones. Una enumeración es básicamente un conjunto de constantes utilizados para representar los posibles valores de un tipo dado. Para representar los días de la semana en C, utilizaríamos:&lt;br /&gt;&lt;blockquote&gt; &lt;span style="color: rgb(0, 0, 102);"&gt;enum diasemana {&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DOMINGO, LUNES, MARTES, MIERCOLES, &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;JUEVES, VIERNES, SABADO&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;};&lt;/span&gt;&lt;/blockquote&gt;Solo que en C, los enums son azúcar sintáctica, es una forma abreviada de definir un grupo de constantes. &lt;span style="font-style: italic;"&gt;diasemana&lt;/span&gt; no es de ninguna forma un &lt;span style="font-style: italic;"&gt;tipo de datos&lt;/span&gt;, son simplemente enteros.&lt;br /&gt;&lt;br /&gt;En Haskell, el código anterior sería:&lt;br /&gt;&lt;blockquote style="color: rgb(0, 0, 102);"&gt;data Diasemana = Domingo | Lunes | Martes | Miercoles&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;| Jueves | Viernes | Sabado&lt;/blockquote&gt;la diferencia está en que, &lt;span style="font-style: italic;"&gt;Diasemana&lt;/span&gt; si es un tipo de datos. Los valores de tipo &lt;span style="font-style: italic;"&gt;Diasemana&lt;/span&gt; no son equivalentes a los enteros y no pueden mezclarse.&lt;br /&gt;&lt;br /&gt;Otro tipo de datos popular son las &lt;span style="font-style: italic;"&gt;estructuras&lt;/span&gt;, que no son mas que un conjunto ordenado de valores de (posiblemente) diferentes tipos. En C una estructura se define del siguiente modo:&lt;br /&gt;&lt;blockquote&gt; &lt;span style="color: rgb(0, 0, 102);"&gt;typedef struct student_type {   &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;char nombre[20];&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;char apellido[20];&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;int edad; } persona;&lt;/span&gt;&lt;/blockquote&gt;en Haskell sería:&lt;br /&gt;&lt;blockquote style="color: rgb(0, 0, 102);"&gt; data Persona = Persona String String Int&lt;/blockquote&gt;&lt;br /&gt;En Haskell, el tipo &lt;span style="font-style: italic;"&gt;Persona&lt;/span&gt; esta formado por la etiqueta 'Persona' (llamado constructor de datos) y seguido por tres valores: dos strings y un entero.&lt;br /&gt;&lt;br /&gt;Finalmente están las uniones. Una unión es una estructura de datos cuyos valores pueden pertenecer a dos o más tipos diferentes. Por ejemplo, en C:    &lt;blockquote style="color: rgb(0, 0, 102);"&gt;typedef struct {float real, imaginario; } cartesiano;&lt;br /&gt;typedef struct {float modulo, angulo; } polar;&lt;br /&gt;union {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cartesiano  c;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;polar p;&lt;br /&gt; } complejo;&lt;/blockquote&gt;En Haskell:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;data Complejo = Cartesiano Float Float | Polar Float Float&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;Como se ve, usando solo los ADT se logra lo que en otros lenguajes requiere tres tipos diferentes de estructura de datos. Y no solo eso, sino que el resultado es más compacto.&lt;br /&gt;&lt;br /&gt;Otra ventaja de los ADT viene, al menos para mí, del aspecto sicológico. Mientras que en C, fiel a su tradición de eficiencia y cercanía a la "maquina desnuda", estas estructuras de datos definen alineamientos en memoria, los ADTs ofrecen una definición más abstracta. Leer un ADT es leer las estructuras de datos del problema &lt;span style="font-style: italic;"&gt;en su propio lenguaje&lt;/span&gt;. Leer un &lt;span style="font-style: italic;"&gt;enum, union &lt;/span&gt;o &lt;span style="font-style: italic;"&gt;struct&lt;/span&gt; de C, es leer la traducción de las estructuras de datos al lenguaje del computador.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-2357134676322629499?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/2357134676322629499/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=2357134676322629499' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/2357134676322629499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/2357134676322629499'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2010/01/diversion-con-tipos-de-datos.html' title='Diversión con tipos de datos algebraícos'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-5333928556960371110</id><published>2009-12-30T17:27:00.000-08:00</published><updated>2010-01-14T12:30:22.283-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><category scheme='http://www.blogger.com/atom/ns#' term='Funcional'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>Tipos polimorficos en Haskell</title><content type='html'>Una vez pasado el shock inicial, la información sobre los tipos de las expresiones en haskell pueden ser realmente útiles. Si revisas una librería en haskell y ves la firma de las funciones, prácticamente sabrás todo lo que necesitas conocer sobre las mismas.&lt;br /&gt;&lt;br /&gt;Este hecho siempre me sorprendió. Ver la firma de una función en C no ofrece la misma cantidad de información, incluso para alguien como yo, más familiarizado con C que con Haskell. Y desde luego, los lenguajes de script no ofrecen ninguna garantía sobre los parametros que reciben sus funciones.&lt;br /&gt;&lt;br /&gt;Pero, por que? Como es que la firma de una función en Haskell ofrece tanta información? No entendía la respuesta hasta leer &lt;a href="http://book.realworldhaskell.org"&gt;Real World Haskell&lt;/a&gt;. Por ejemplo, la siguiente declaración:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;    qsort :: Ord a =&gt; [a] -&gt; [a]&lt;/blockquote&gt;&lt;br /&gt;Nos dice que qsort es una función polimorfica que toma una lista de elementos del tipo a y devuelve una lista del mismo tipo. El único dato que conocemos sobre el tipo &lt;span style="font-style: italic;"&gt;a&lt;/span&gt; es que es de la clase &lt;span style="font-style: italic;"&gt;Ord&lt;/span&gt;, es decir que sobre él están definidas las comparaciones de igualdad, mayor que, menor que, etc.&lt;br /&gt;&lt;br /&gt;Lo interesante del caso, es que cuando digo &lt;span style="font-style: italic;"&gt;conocemos&lt;/span&gt;, me refiero no solo a las personas que leen el código, sino también a la función. La función qsort no sabe algo sobre &lt;span style="font-style: italic;"&gt;a&lt;/span&gt; que nosotros ignoremos. Cualquier función definida sobre &lt;span style="font-style: italic;"&gt;a&lt;/span&gt; distinta de la clase &lt;span style="font-style: italic;"&gt;Ord&lt;/span&gt; es inaccesible a qsort. Es decir, sea lo que sea que qsort haga, solo puede comparar los elementos de [a]. Y dado que las funciones en Haskell son puras, no tiene acceso a variables externas, por lo que la lista resultante depende solo de la lista de entrada.&lt;br /&gt;&lt;br /&gt;Esto reduce enormemente las posibilidades de qsort. Sentido común en la elección del nombre por parte del autor y una linea de documentación nos dirá el resto de lo que necesitamos saber: qsort devuelve una lista con los elementos de su argumento ordenados.&lt;br /&gt;&lt;br /&gt;Otro ejemplo es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;mistery :: (a -&gt; b) -&gt; [a] -&gt; [b]&lt;/blockquote&gt;&lt;br /&gt;El nombre de la función ha sido ofuscado deliberadamente. Para quienes no conocen Haskell, el primer argumento (a -&gt; b) es una función que toma argumentos de tipo &lt;span style="font-style: italic;"&gt;a&lt;/span&gt; y devuelve elementos del tipo &lt;span style="font-style: italic;"&gt;b&lt;/span&gt;. De nuevo, como no sabemos absolutamente nada sobre los tipos a y b, &lt;span style="font-style: italic;"&gt;mistery&lt;/span&gt; no puede usar otra información más que la dada para llevar a cabo su cometido.&lt;br /&gt;&lt;br /&gt;Puedes adivinar que hace mistery?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-5333928556960371110?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/5333928556960371110/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=5333928556960371110' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/5333928556960371110'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/5333928556960371110'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2009/12/tipos-polimorficos-en-haskell.html' title='Tipos polimorficos en Haskell'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-5724202645104829367</id><published>2008-08-05T12:53:00.000-07:00</published><updated>2009-05-20T15:14:44.464-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='zope'/><title type='text'>Autenticacion LDAP en zope2</title><content type='html'>La autenticación LDAP en zope2 se ha hecho mas fácil con los eggs. Basta con agregar al listado de eggs necesarios en buildout el nombre Products.PloneLDAP.&lt;br /&gt;Este producto depende a su vez de&lt;br /&gt;&lt;ul&gt;&lt;li&gt;python-ldap&lt;/li&gt;&lt;li&gt;LDAPUserFolder&lt;/li&gt;&lt;li&gt;LDAPMultiPlugins&lt;/li&gt;&lt;/ul&gt;todos ellos descargados automáticamente durante el buildout.&lt;br /&gt;&lt;br /&gt;Ahora, Centos 4 viene con una versión antigua de LDAP que no es compatible con &lt;span style="font-style: italic;"&gt;python-ldap&lt;/span&gt;. Para compilar este paquete hay que instalar &lt;span style="font-style: italic;"&gt;ldap-2.3&lt;/span&gt; en paralelo con la versión de la distro. Una vez hecho esto hay que bajar y generar una versión local del egg &lt;span style="font-style: italic;"&gt;python-ldap&lt;/span&gt;, que se enlace las nuevas librerías:&lt;br /&gt;&lt;blockquote style="color: rgb(0, 0, 153);"&gt;# Bajar solamente el egg&lt;br /&gt;$ easy_install -b downloads/ python-ldap&lt;br /&gt;$ cd downloads/python-ldap&lt;br /&gt;&lt;/blockquote&gt;Luego se edita el archivo &lt;span style="font-style: italic;"&gt;setup.cfg&lt;/span&gt; cambiando las variables &lt;span style="font-style: italic;"&gt;library_dirs&lt;/span&gt; e &lt;span style="font-style: italic;"&gt;include_dirs&lt;/span&gt; para que apunten al directorio de librerías e includes de la nueva versión de LDAP. Una vez hecho esto, se genera el egg&lt;br /&gt;&lt;blockquote style="color: rgb(0, 0, 153);"&gt;$ ./setup.py bdist_egg&lt;/blockquote&gt;&lt;br /&gt;Este egg puede luego ser copiado en el directorio egg de la instancia a desarrollar.&lt;br /&gt;&lt;br /&gt;Para activar la autenticación LDAP, desde la interface ZMI del zope se visita la carpeta acl_user del sitio plone. En ella se cre un &lt;span style="font-style: italic;"&gt;'Plone LDAP Plugin'&lt;/span&gt;, digamos con el nombre &lt;span style="font-style: italic;"&gt;ldapmaster&lt;/span&gt;. Luego todas sus funcionalidades deben ser activadas (&lt;span style="font-style: italic;"&gt;site/acl_users/ldapmaster&lt;/span&gt; lengüeta &lt;span style="font-style: italic;"&gt;"activate"&lt;/span&gt;). Finalmente hay que prioritizar el uso de la autenticación ldap, visitando &lt;span style="font-style: italic;"&gt;site/acl_users/plugins&lt;/span&gt;, seleccionando primero el Plugin Type &lt;span style="font-style: italic;"&gt;"Properties Plugins"&lt;/span&gt; y poniendo de primero a &lt;span style="font-style: italic;"&gt;ldapmaster&lt;/span&gt;. Luego se hace lo propio &lt;span style="font-style: italic;"&gt;"UserManagement Plugins"&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-5724202645104829367?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/5724202645104829367/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=5724202645104829367' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/5724202645104829367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/5724202645104829367'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2008/08/autenticacion-ldap-en-zope2.html' title='Autenticacion LDAP en zope2'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-2522089414280428741</id><published>2008-08-05T12:34:00.000-07:00</published><updated>2009-05-20T15:14:10.950-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='zope'/><title type='text'>Desarrollo y Despliegue en zope2+Plone3</title><content type='html'>A continuación sigue como desarrollar y desplegar un sitio basado en zope 2 y Plone 3 usando egg.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Instalar el entorno virtual&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Como siempre comenzamos instalando un entorno virtual para trabajar con comodidad&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# con una version previa de easy_install, instalar virtualenv&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ wget http://peak.telecommunity.com/dist/ez_setup.py&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ sudo python2.4 ez_setup&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ sudo easy_install-2.4 virtualenv&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;&lt;br /&gt;# crear el entorno virtual de python &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# y comenzar a trabajar en el&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ virtualenv ~/entorno&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ cd ~/entorno&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ source bin/activate&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Instalación del Zope 2 y Plone 3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Luego instalamos ZopeSkel, que nos generará un buildout.cfg que se adaptará al tipo de proyecto de zope2 que querramos:&lt;br /&gt;&lt;blockquote style="color: rgb(0, 0, 153);"&gt;$ easy_install ZopeSkel&lt;/blockquote&gt;&lt;br /&gt;Podemos ver que clase de proyectos podemos crear con ZopeSkel del siguiente modo:&lt;br /&gt;&lt;blockquote style="color: rgb(0, 0, 153);"&gt;$ paster create --list-templates&lt;/blockquote&gt;&lt;br /&gt;Luego creamos el proyecto zope2+plone3 propiamente, hacemos el bootstrap y el buildout:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ paster create -t plone3_buildout myPlone&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ cd myPlone&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ python bootstrap&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ bin/buildout&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;Posteriormente podremos usar la opción -No en el buildout para que no chequee que cada egg bajado tenga la última versión.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;/span&gt;Para arrancar el zope:&lt;br /&gt;&lt;blockquote style="color: rgb(0, 0, 153);"&gt;$ bin/instance fg&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Despliegue&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Como ya es costumbre, los productos que deseemos agregar a nuestra instancia se agregan a la variable egg de buildout.cfg y se vuelve a reconstruir el proyecto. Si el producto tiene algún archivo de configuración zcml, este debe ser agregado en la sección zcml.&lt;br /&gt;&lt;br /&gt;Los eggs de desarrollo deben ser registrados tanto en eggs, como en la variable develop.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Desarrollo&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Para desarrollar un egg, se usa de nuevo paster en el directorio src de la instancia en cuestion:&lt;br /&gt;&lt;blockquote style="color: rgb(0, 0, 153);"&gt;$ paster create -t plone mi.producto&lt;/blockquote&gt;&lt;br /&gt;Como siempre las dependencias de este producto van en su setup.cfg.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-2522089414280428741?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/2522089414280428741/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=2522089414280428741' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/2522089414280428741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/2522089414280428741'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2008/08/desarrollo-y-despliegue-en-zope2plone3.html' title='Desarrollo y Despliegue en zope2+Plone3'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-1564925959566862666</id><published>2008-02-21T07:20:00.000-08:00</published><updated>2009-05-20T15:13:30.666-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='zope'/><title type='text'>Desarrollo y Despliegue en zope</title><content type='html'>Siguiendo con los apuntes de zope 3, aquí esta la versión aumentada y corregida de como trabajar con zope. Básicamente se quiere llevar a cabo dos actividades: desarrollo (development) y despliegue (deployment).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Preconfiguración&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Antes de desarrollar cualquier aplicación es conveniente tener un entorno sano y reproducible y de preferencia trabajar en un sandbox personal. Ya vimos una opción para crear este entorno virtual usando virtual-python. El sucesor de virtual-python es &lt;a href="http://pypi.python.org/pypi/virtualenv"&gt;virtualenv&lt;/a&gt;. Esta aplicación funciona mejor que virtual-python en windows y genera un entorno menos polucionado. Además, instala automaticamente easy_install y un script de activación del entorno:&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# con una version previa de easy_install, instalar virtualenv&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ wget http://peak.telecommunity.com/dist/ez_setup.py&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ sudo python2.4 ez_setup&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ sudo easy_install-2.4 virtualenv&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;&lt;br /&gt;# crear el entorno virtual de python &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# y comenzar a trabajar en el&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ virtualenv ~/entorno&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ cd ~/entorno&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ source bin/activate&lt;br /&gt;&lt;br /&gt;# instalar zope-project&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;$ easy_install zopeproject&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102);"&gt;&lt;br /&gt;# instalar zc.buildout&lt;/span&gt;&lt;br /&gt;$ easy_install zc.buildout&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;El ultimo comando se encarga de fijar algunas variables de entorno, modificar el path para usar el interprete de python del entorno virtual y modificar el prompt para indicar que el entorno esta activo.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Despliegue&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;El despliegue es la creación y configuración del sitio web propiamente. Para crear el sitio de despliegue (una instancia de zope 3) usamos zopeproject dentro de nuestro entorno virtual previamente activado:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# Crear una instancia&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ zopeproject misitio&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;{introducir el login del administrador}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;{introducir la contraseña del administrador}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;{introducir la ruta donde se guardarán los eggs para el proyecto&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;  indicar preferiblemente ~/entorno/lib/python2.4/site-packages/ }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# comenzar a trabajar en el sitio de despliegue&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ cd misitio&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;/blockquote&gt;El sitio se configura en src/misitio/sonfigure.zcml y sus dependencias para la generación del egg se especifican en setup.py, como de costumbre. El script para el buildout es buildout.cfg.&lt;br /&gt;&lt;br /&gt;Como siempre, al agregar o eliminar dependencias, se debe correr bin/buildout.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Desarrollo&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;El desarrollo es la creación de paquetes para zope. Estos paquetes normalmente no tienen utilidad fuera del zope, sino que son las piezas de lego con las que se construye un sitio. Es conveniente que cada paquete de desarrollo resida en su propio directorio y sus requerimientos sean manejados por zc.buildout. Ahora se creará la estructura mínima de un paquete de desarrollo, siempre en el entorno virtual previamente activado:&lt;br /&gt;&lt;blockquote&gt;# Crear el directorio para el buildout del paquete&lt;br /&gt;$ mkdir mipaquete&lt;br /&gt;$ cd mipaquete&lt;br /&gt;$ buildout init&lt;br /&gt;&lt;br /&gt;# Crear la estructura mínima del buildout&lt;br /&gt;$ touch setup.py&lt;br /&gt;$ mkdir -p src/mipaquete&lt;br /&gt;$ touch src/mipaquete/__init__.py&lt;br /&gt;&lt;/blockquote&gt;La estructura básica de buildout.cfg es&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;[buildout]&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;develop = .&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;parts = test&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;eggs-directory =  /home/jdinunci/apps/webdev/lib/python2.4/site-packages/&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;  {ruta donde yo guardo los eggs}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;[test]&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;recipe = zc.recipe.testrunner&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;eggs = mipaquete [test]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;La estructura básica de setup.py es&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;import os&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;from setuptools import setup, find_packages&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;def read(*rnames):&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;setup (&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    name='mipaquete',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    version='0.1',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    author = "Jose Dinuncio",&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    author_email = "micorreo@midominio.org",&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    description = "Mi paquete",&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    license = "GPL",&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    keywords = "zope3",&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    classifiers = [&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        'Environment :: Web Environment',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        'Intended Audience :: Developers',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        'Programming Language :: Python',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        'Natural Language :: English',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        'Operating System :: OS Independent',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        'Topic :: Internet :: WWW/HTTP',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        'Framework :: Zope3'],&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    packages = find_packages('src'),&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    include_package_data = True,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    package_dir = {'':'src'},&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    # linea de abajo solo necesaria para&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    # paquetes virtuales&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    #namespace_packages = ['reduc'],&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    extras_require = dict(&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        test = [&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;            'zope.testing',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;            'zope.app.container [test]',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;            ],&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;),&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    install_requires = [&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        'setuptools',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        'zope.interface',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        'ZODB3',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        'zope.schema',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        'zope.app.container',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        'zope.app.content',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        'zope.dublincore',&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        ],&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;dependency_links =&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;['http://download.zope.org/distribution'],&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    zip_safe = False,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    )&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;En mi caso, mis paquetes usan paquetes virtuales, por lo que suelen llamarse reduc.mipaquete, lo cual implica ligeras modificaciones en el procedimiento&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;#Crear el directorio para el buildout del paquete&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt; $ mkdir  reduc.mipaquete&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt; $ cd reduc.mipaquete&lt;br /&gt;$ buildout init&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt; # Crear la estructura mínima del buildout&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt; $ touch setup.py&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt; $ mkdir -p src/reduc/mipaquete&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ touch src/reduc/mipaquete/__init__.py&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# Crear el paquete virtual reduc&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;$ echo "__import__('pkg_resources').declare_namespace(__name__)"&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;   &gt; src/reduc/__init__.py&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;En este caso, hay que agregar una configuración a setup.py para el manejo del paquete virtual:&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;&lt;blockquote&gt;namespace_packages = ['reduc'],&lt;/blockquote&gt;&lt;/span&gt;&lt;br /&gt;Estos paquetes en desarrollo pueden ser incluidos en el sitio de despliegue con la directiva develop&lt;blockquote style="color: rgb(51, 102, 102);"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;[buildout]&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;develop = .&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;        &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;    &lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;../mipaquete&lt;/span&gt;&lt;/blockquote&gt;&lt;br /&gt;Al ejecutar bin/buildout, se crea un enlace en develop-egg que permite que los paquetes sean encontrados.&lt;br /&gt;&lt;br /&gt;Este es el ciclo depurado para el desarrollo y despliegue en python. Aún puede agregarse mas comodidad al mismo, como agregar al buildout la descarga automatica de paquetes de desarrollo vía svn.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-1564925959566862666?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/1564925959566862666/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=1564925959566862666' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/1564925959566862666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/1564925959566862666'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2008/02/desarrollo-y-despliegue-en-zope.html' title='Desarrollo y Despliegue en zope'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-1228858525943223213</id><published>2008-02-15T12:07:00.001-08:00</published><updated>2009-05-20T15:12:53.108-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='zope'/><title type='text'>Como obtener paquetes de Zope via svn</title><content type='html'>Lo ideal es obtener los paquetes de zope vía easy_install o buildout. Sin embargo, una importante cantidad de paquetes es estado de desarrollo, pero aún estables, se encuentran en un repositorio de subversion.&lt;br /&gt;&lt;br /&gt;La primera pregunta es: ¿Como saber que hay en ese repositorio? Una forma fácil es visitando &lt;a href="http://svn.zope.org/"&gt;http://svn.zope.org&lt;/a&gt;. Supongamos que eliges &lt;a href="http://svn.zope.org/z3c.weblog/"&gt;http://svn.zope.org/z3c.weblog/&lt;/a&gt;. Después de ubicar el paquete en cuestión, es solo cosa de descargando usando el svn, mas con la siguiente salvedad: se sustituye el protocolo por svn y se prefija la url con repos/main/:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;blockquote style="color: rgb(0, 0, 153);"&gt;&lt;span style="font-weight: bold;"&gt;svn co svn:&lt;/span&gt;//svn.zope.org/&lt;span style="font-weight: bold;"&gt;repos/main/&lt;/span&gt;z3c.weblog z3c.weblog&lt;/blockquote&gt;Una vez hecho esto, se debe generar el entorno para el buildout y ejecutar el buildout propiamente:&lt;br /&gt;&lt;blockquote style="color: rgb(0, 0, 153);"&gt;# bootstrap&lt;br /&gt;# bin/buildout&lt;br /&gt;&lt;/blockquote&gt;O, si ya se dispone de un buildout, simplemente invocarlo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-1228858525943223213?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/1228858525943223213/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=1228858525943223213' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/1228858525943223213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/1228858525943223213'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2008/02/como-obtener-paquetes-de-zope-via-svn.html' title='Como obtener paquetes de Zope via svn'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-3653612021369992640</id><published>2008-02-01T16:16:00.000-08:00</published><updated>2008-02-15T13:25:36.090-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='zope'/><title type='text'>Desarrollando con zc.buildout</title><content type='html'>Siguiendo con el desvío tomado en Huevos y Constructores, abordaremos el desarrollo de paquetes en python usando &lt;span style="font-weight: bold;"&gt;zc.buildout&lt;/span&gt;. La instancia de zope que creamos con &lt;span style="font-weight: bold;"&gt;zopeproject&lt;/span&gt; es un proyecto manejado por buildout, por lo que es de suma importancia entender como funciona este de manera aislada. Para ello crearemos un paquete en python con una implementación de ejemplo.&lt;br /&gt;&lt;br /&gt;Por que usar buildout? Dado que queremos hacer fácilmente instalable nuestro paquete por terceras personas, requerimos algún método para empaquetarlo y distribuirlo. Podríamos usar &lt;span style="font-weight: bold;"&gt;distutil&lt;/span&gt;, pero durante el desarrollo con cada cambio hecho al código deberiamos generar la distribución e instalarla antes de hacer una prueba. Adicionalmente, para hacer la instalación se requiere permisología de root.&lt;br /&gt;&lt;br /&gt;Otras ventajas de builtout sobre distutils es que este usa &lt;span style="font-weight: bold;"&gt;setuptools&lt;/span&gt;, por lo que podemos resolver los problemas de dependencias y versiones con los que se enfrentaría quien tratara de instalar el paquete. buildout se ocupa además de preconfigurar el paquete antes de hacer la instalación o pruebas.&lt;br /&gt;&lt;br /&gt;Para instalar zc.buildout se requiere setuptools y se recomienda virtual-python (veáse Instalando Zope 3).&lt;br /&gt;&lt;br /&gt;Para procesar un paquete o aplicación &lt;span style="font-weight: bold;"&gt;&lt;/span&gt;con buildout se requiere un archivo buildout.cfg que defina el entorno que el paquete necesita:&lt;br /&gt;&lt;blockquote style="font-family: courier new; color: rgb(0, 0, 153);"&gt;[buildout]&lt;br /&gt;develop=.&lt;br /&gt;...&lt;br /&gt;&lt;/blockquote&gt;La estructura del archivo buildout.cfg es una serie de &lt;span style="font-weight: bold;"&gt;secciones&lt;/span&gt; cuyo nombre aparece entre corchetes, seguida por una serie de pares clave=valor que definen la sección. [buildout] es la sección principal y la única requerida.&lt;br /&gt;&lt;br /&gt;buildout.cfg define una serie de &lt;span style="font-weight: bold;"&gt;partes&lt;/span&gt; o elementos necesarios para que la aplicación funcione. Cada parte se define en una sección diferente. Cada parte es procesada por un &lt;span style="font-weight: bold;"&gt;recipe&lt;/span&gt; (un programa en python para instalar y actualizar la parte). Las demas lineas de una sección sirver para configurar el recipe. Hay &lt;a href="http://pypi.python.org/pypi?%3Aaction=search&amp;amp;term=recipe&amp;amp;submit=search"&gt;una gran variedad&lt;/a&gt; de recipes para distintas funciones, como descargar eggs, compilar aplicaciones, correr la batería de pruebas de un paquete,e tc. En caso de necesidad el desarrollador puede crear sus propios recipes.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Desarrollando un paquete con buildout&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Comenzamos desarrollando un paquete normal en python&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# mkdir blah&lt;/span&gt; &lt;span style="color: rgb(0, 0, 153);"&gt;&lt;br /&gt;# cd blah&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# mkdir src   {aquí va el código fuente de los paqutes a desarrollar}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# mkdir src/blah&lt;br /&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 0, 153);"&gt;# ... {se agregan los módulos al paquete blah}&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;Este paquete será distribuido con setuptools, por lo que debemos crear un archivo blah/setup.py que defina su distribución:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# blah/setup.py&lt;/span&gt; &lt;span style="color: rgb(0, 0, 153);"&gt;&lt;br /&gt;from setuptools import setup, find_packages&lt;/span&gt;  &lt;span style="color: rgb(0, 0, 153);"&gt;&lt;br /&gt;setup(name='blah',&lt;/span&gt; &lt;span style="color: rgb(0, 0, 153);"&gt;      version='0.1',&lt;/span&gt;&lt;br /&gt;          &lt;span style="color: rgb(0, 0, 153);"&gt;packages=find_packages("src"),&lt;/span&gt;&lt;br /&gt;          &lt;span style="color: rgb(0, 0, 153);"&gt;package_dir={"": "src"},&lt;/span&gt; &lt;br /&gt;         &lt;span style="color: rgb(0, 0, 153);"&gt;# Notese que los requisitos del paquete son indicados&lt;/span&gt;&lt;br /&gt;         &lt;span style="color: rgb(0, 0, 153);"&gt;# aquí para que setuptools pueda generar&lt;br /&gt;         # correctamente su egg&lt;/span&gt;   &lt;br /&gt;         &lt;span style="color: rgb(0, 0, 153);"&gt;install_requires=[&lt;/span&gt; &lt;span style="color: rgb(0, 0, 153);"&gt;          'zope.tal'&lt;/span&gt; &lt;span style="color: rgb(0, 0, 153);"&gt;          ],&lt;/span&gt; &lt;span style="color: rgb(0, 0, 153);"&gt;      )&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;Hasta este punto tenemos un paquete convencional de python, listo para ser distribuído via setuptools. Ahora hay que convertir el directorio de trabajo en un directorio manejado por buildout.&lt;br /&gt;&lt;br /&gt;Ahora, se define el archivo buildout.cfg que determinará como generar la aplicación&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;[buildout]&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;develop=.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;parts=me&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;[me]&lt;/span&gt; &lt;span style="color: rgb(0, 0, 153);"&gt;recipe=zc.recipe.egg&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;eggs=zope.tal&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;Este archivo define una parte llamada 'me', la cual para ser construida requiere el recipe encargado de descargar eggs. El único egg a descargar será zope.tal.&lt;br /&gt;&lt;br /&gt;Pero aún falta en manejar este proyecto a traves de buildout. Para crear la infraestructura necesaria, hay que hacer un bootstrap. Este procedimiento se realiza una única vez en la vida del proyecto:&lt;br /&gt;&lt;blockquote style="color: rgb(0, 0, 153);"&gt;# ruta-hacia-buildout/buildout bootstrap&lt;/blockquote&gt;&lt;br /&gt;(Desde luego, buildout debe estar instalado, cosa fácil gracias a easy_install).&lt;br /&gt;&lt;br /&gt;buildout creará un directorio bin donde instalará su ejecutable y cualquier otro requerido por las dependencias. Creará además un directorio eggs donde instalará los eggs necesarios por esta aplicación, un directorio develop-eggs donde creará referencia a los eggs que esta aplicación defina y un directorio parts, para ser utilizado por las partes del archivo de configuración.&lt;br /&gt;&lt;br /&gt;Ya con toda la infraestructura en su lugar, para asegurar que la aplicación tenga todos sus requerimientos instalados basta con ejecutar&lt;br /&gt;&lt;blockquote style="color: rgb(0, 0, 153);"&gt;# buildout&lt;/blockquote&gt;Con cada cambio en las dependencias es necesario re-ejecutar el comando, para que satisfaga las nuevas necesidades de la aplicación.&lt;br /&gt;&lt;br /&gt;Jugando con las partes y los recipes se puede automatizar el proceso de instalación de las dependencias de la aplicación. Otras funciones determinan si se descargará la versión mas nueva de un paquete o una en especifico.&lt;br /&gt;&lt;br /&gt;Se puede generar la distribución de los paquetes por medio de setuptools o por medio de buildout. En el último caso, los comandos son:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# bin/buildout setup . sdist           {distribución fuente}&lt;/span&gt; &lt;span style="color: rgb(0, 0, 153);"&gt;&lt;br /&gt;# bin/buildout setup . bdist           {binarios}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;# bin/buildout setup . bdist_egg   {bnarios en eggs}&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;/blockquote&gt;La fuente autoritativa de zc.buildout se encuentra en &lt;a href="http://pypi.python.org/pypi/zc.buildout"&gt;http://pypi.python.org/pypi/zc.buildout&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-3653612021369992640?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/3653612021369992640/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=3653612021369992640' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/3653612021369992640'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/3653612021369992640'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2008/02/desarrollando-con-zcbuildout.html' title='Desarrollando con zc.buildout'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-2187807747287318976</id><published>2008-02-01T11:38:00.000-08:00</published><updated>2008-02-05T12:04:19.278-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='zope'/><title type='text'>Huevos y Constructores</title><content type='html'>&lt;p  style="font-family:arial;"&gt;Antes de proseguir con el desarrollo en zope es conveniente tomar un desvío hacia dos tecnologías usadas por zope que pueden no ser conocidas por los desarrolladores en python: los &lt;span style="font-weight: bold;"&gt;eggs&lt;/span&gt; y &lt;span style="font-weight: bold;"&gt;buildout&lt;/span&gt;.&lt;/p&gt;&lt;br /&gt;Los eggs son una forma conveniente de distribuir paquetes de python. Pueden pensarse como el equivalente a los .jar de java, solo que con mayor riqueza. Los eggs son una extensión al mecanismo tradicional de distribución de paquetes en python, ofrecido por &lt;span style="font-weight: bold;"&gt;distutils&lt;/span&gt;.&lt;br /&gt;&lt;p  style="font-family:arial;"&gt;distutils es la herramienta incorporada en python para la compilación e instalación de paquetes. Normalmente el usuario descarga un archivo .tgz con la fuente del paquete, lo descomprime y ejecuta el archivo &lt;span style="font-weight: bold;"&gt;setup.py&lt;/span&gt; que este contiene. setup.py invoca a distutils que compila (de ser necesario) e instala el paquete en un lugar donde pueda ser encontrado por python.&lt;/p&gt;&lt;p  style="font-family:arial;"&gt;Los eggs mejoran este proceso. Son paquetes ya compilados, por lo que no requieren herramientas de desarrollo adicionales (compiladores, etc). Pueden estar comprimidos, siendo mas fácilmente manipulables. Además, ofrecen una metadata mas rica, lo cual permite la detección de dependencias.&lt;/p&gt;&lt;p face="arial"&gt;Esta última característica es lo que permite usar eggs para construir un repositorio de aplicaciones con instalación simplificada. El programa &lt;span style="font-weight: bold;"&gt;easy_install.py&lt;/span&gt; se aprovecha estas características para permitir una instalación de las aplicaciones y sus dependencias con una simple instrucción.&lt;/p&gt;El crear un egg es tan simple como crear un paquete con distutils. Solo se necesita tener instalado el paquete &lt;span style="font-weight: bold;"&gt;setuptools&lt;/span&gt; (el cual es en si mismo un egg que puede ser instalado automáticamente por easy_install). Si el egg va a ser distribuido empaquetado como un zip, entonces debe seguirse unas convenciones adicionales.&lt;br /&gt;&lt;p style="font-family: arial;"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: arial;"&gt;La otra tecnología es &lt;span style="font-weight: bold;"&gt;buildout&lt;/span&gt;. El término en general se refiere a todo lo necesario para la construcción e implementación de una aplicación. Cuando un desarrollador esta trabajando en una aplicación con muchas dependencias, necesita herramientas para automatizar su configuración y seguir las versiones de cada paquete usado. La gente de zope desarrolló el paquete &lt;span style="font-weight: bold;"&gt;zc.buildout&lt;/span&gt; con esta finalidad.&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: arial;"&gt;zc.buildout permite crear entornos para el desarrollo que sean fácilmente repetibles. De esta manera, el desarrollador podrá trabajar con frameworks complejos como zope y trasladar su trabajo a otro equipo. El resultado final de zc.buildout es un egg con la información exacta de todas las dependencias, versiones y todos sus procesos de configuración. Al instalar este egg en un tercer equipo se obtendrá una copia exacta del entorno en el equipo original.&lt;br /&gt;&lt;/p&gt;El ingrediente final en la entrada anterior fue el paquete zopeproject. Este paquete instala un comando del mismo nombre que genera un buildout preconfigurado para iniciar un proyecto con zope.&lt;br /&gt;&lt;br /&gt;En entradas posteriores trataré el uso de los eggs y de zc.buildout en desarrollos de python independientes de zope para mostrar su utilidad general. Esto permitirá comprender de forma mas fácil que su uso en zope es conveniente mas dispensable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-2187807747287318976?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/2187807747287318976/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=2187807747287318976' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/2187807747287318976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/2187807747287318976'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2008/02/huevos-y-constructores.html' title='Huevos y Constructores'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-8521254170770531655</id><published>2008-02-01T06:18:00.000-08:00</published><updated>2008-02-01T11:46:53.162-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='zope'/><title type='text'>Instalando Zope 3</title><content type='html'>La presente explicación aplica para usuarios de Linux y otras formas de Unix.&lt;br /&gt;&lt;br /&gt;La mas reciente versión de Zope es la 3.4.0Beta. La serie 3.4 es la primera en migrar hacia la distribución en eggs. Esto hace que su proceso de instalación sea diferente al tradicional descomprimir-configurar-compilar-instalar. Los eggs son paquetes de python con sus dependencias indicadas y una infraestructura (easy_install) para obtenerlos e instalarlos automáticamente.&lt;br /&gt;&lt;br /&gt;Otro punto a considerar es que zope recomienda el python 2.4 mas su paquete de desarrollo, los cuales podría no ser los instalados en el sistema.&lt;br /&gt;&lt;br /&gt;Para trabajar con mayor comodidad y seguridad con zope es mejor hacerlo como un usuario normal y no hacer una instalación como root en las rutas por defecto. Para ello es recomendable crear un entorno virtual para python. Baja &lt;a href="http://peak.telecommunity.com/dist/virtual-python.py"&gt;virtual-python.py&lt;/a&gt; y ejecutalo:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;span style="color: rgb(0, 0, 153);"&gt;# python2.4 bin/virtual-python.py --prefix=~/zope3/&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Esto creará una carpeta zope3 en tu directorio home que contendrá una copia ligera del python2.4, sus archivos include y sus librerías. Aquí podrás instalar cualquier aplicación o paquete hecho en python sin tener necesidad de privilegios de administración.&lt;br /&gt;&lt;br /&gt;El siguiente paso es instalar easy_install, la aplicación que maneja los eggs y permite instalar paquetes de python de manera automatica. Baja &lt;a href="http://peak.telecommunity.com/dist/ez_setup.py"&gt;ez_setup.py&lt;/a&gt; y ejecutalo:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;    # ~/zope3/bin/python bin/ez_setup.py&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hasta este punto no has hecho nada que sea especifico de zope. Solo tienes un entorno propio de python, con soporte para instalación de eggs. Eso esta por cambiar. Con la magia de easy_install instalaremos un único paquete que te permitirá crear instancias de zope y bajará todas las librerías necesarias:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;    # ~/zope/bin/easy_install zopeproject&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Es en este punto que podemos crear nuestra primera instancia de zope3, llamemosla &lt;span style="font-style: italic;"&gt;webdev&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:courier new;" &gt;    # ~/zope/bin/zopeproject webdev&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;zopeproject preguntará por un login y contraseña para el administrador de la instancia y por el lugar en el cual descargará los eggs del zope. Responde a esta pregunta con  ~/zope/lib/python2.4 /site-packages. A continuación zopeproject bajará zc.buildout que es un paquete encargado de construir aplicaciones, descargando automáticamente sus dependencias. Si es la primera vez que ejecutas zopeproject preparate a esperar unos buenos minutos mientras descarga todas las librerías que conforman zope. Invocaciones posteriores serán mucho mas rapidas mientras sigas indicando la misma ruta de descarga de los eggs.&lt;br /&gt;&lt;br /&gt;Al finalizar el proceso tendras dentro de zope una carpeta webdev. Esta carpeta contiene tu instancia zope. Para iniciar tu instancia puedes ejecutar&lt;br /&gt;&lt;br /&gt;    &lt;span style="color: rgb(0, 0, 153);"&gt;# ~/zope/webdev/bin/webdev-ctl fg&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;y puedes ver a la aplicación corriendo en http://localhost:8080&lt;br /&gt;&lt;br /&gt;Las fuentes para esta entrada están &lt;a href="http://wiki.zope.org/zope3/Zope340b2"&gt;aquí&lt;/a&gt; y &lt;a href="http://pypi.python.org/pypi/zopeproject"&gt;aquí&lt;/a&gt;, solo que de forma menos digerida.&lt;br /&gt;&lt;br /&gt;En este punto solo queda comenzar a desarrollar tu propia aplicación en zope y un poco de conocimiento de &lt;a href="http://pypi.python.org/pypi/zc.buildout"&gt;zc.buildout&lt;/a&gt; para el momento final en que empaquetaras tu aplicación.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-8521254170770531655?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/8521254170770531655/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=8521254170770531655' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/8521254170770531655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/8521254170770531655'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2008/02/instalando-zope-3.html' title='Instalando Zope 3'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-8332667563784234254</id><published>2008-02-01T06:06:00.000-08:00</published><updated>2008-02-01T06:23:13.870-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='zope'/><title type='text'>zope 2 y  zope 3</title><content type='html'>La nueva versión de Zope es Zope 3. Esta es una reescritura desde cero de su anterior y también magnifico producto Zope 2. Zope 2 introdujo conceptos interesantes como el desarrollo de aplicaciones a traves del web, almacenar los componentes en una base de datos orientada a objetos y permisología basada en roles.&lt;br /&gt;&lt;br /&gt;Sin embargo, extender Zope 2 no era fácil. Adicionalmente conforme la aplicación fue evolucionando, es código se volvió mas y mas desordenado. La aplicación había sobrepasado su diseño original.&lt;br /&gt;&lt;br /&gt;Luego se creó el concepto de arquetipos. Desarrollar componentes con arquetipos era una tarea casi trivial: se indicaban los campos que definían a los objetos o componentes por una parte y las funciones que los manipulaban por la otra. La información de los campos era usada para generar las páginas web automáticamente y solo bastaba hacer el enlace con el funciones.&lt;br /&gt;&lt;br /&gt;Ese fue el detonante para Zope 3. Si desarrollar una aplicación dentro de Zope era mucho mas fácil usando arquetipos, por que no desarrollar el Zope mismo bajo este concepto? Los arquetipos se convirtieron en interfaces, componentes, adaptadores y utilidades y una aplicación casi monolítica se convirtió en un archipielago de pequeños y simples componentes interactuando entre si.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-8332667563784234254?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/8332667563784234254/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=8332667563784234254' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/8332667563784234254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/8332667563784234254'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2008/02/zope-2-y-zope-3.html' title='zope 2 y  zope 3'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-8229038484173516365</id><published>2008-02-01T05:47:00.000-08:00</published><updated>2008-02-01T06:24:19.205-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='zope'/><title type='text'>Desarrollo web con zope</title><content type='html'>A principios de este año retomé un viejo amor no correspondido con Zope. Zope es un servidor de aplicaciones con favoritismo hacia el web escrito casi totalmente en python.&lt;br /&gt;&lt;br /&gt;Zope ofrece un framework para el manejo de contenido a través del web. Es como un lego que permite armar pieza por pieza una aplicación web. Para quienes gustan de los buzzwords es un &lt;span style="font-weight: bold;"&gt;CMF&lt;/span&gt; con una &lt;span style="font-weight: bold;"&gt;base de datos transaccional orientada a objetos&lt;/span&gt; y con capacidades de diseño a través del web. Que hace a zope atractivo? Un diseño elegante con separación de responsabilidades. Zope mantiene religiosamente separados código y html.&lt;br /&gt;&lt;br /&gt;Pero su influencia va mas allá de si mismo. El corazón del Zope, el ZCA (Zope Component Architecture) es usado por terceras partes como &lt;a class="reference" href="http://wiki.creativecommons.org/CcPublisher"&gt;Creative Commons Publisher&lt;/a&gt;, &lt;a class="reference" href="http://gaphor.devjavu.com/"&gt;Gaphor&lt;/a&gt; o &lt;a class="reference" href="http://launchpad.net/"&gt;Launchpad&lt;/a&gt;, aplicaciones estas que no tienen que ver con el web. Zope ha sido un motor en el desarrollo de python hasta el punto que se ha llegado a decir que &lt;a href="http://dirtsimple.org/2007/01/where-zope-leads-python-follows.html"&gt;donde Zope guia, python le sigue&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Desde luego, Zope no es perfecto. Al ser un framework, esto le impone al desarrollador el conocer la arquitectura del mismo para poder interactuar con él. Esto significa un costo de entrada pronunciado. Luego de unos intentos en falso, gracias a &lt;a href="http://worldcookery.com/"&gt;Web Component Development with Zope 3&lt;/a&gt;, he comenzado a cosechar mis primeros resultados sobre los que comentaré en futuras notas.&lt;span style="display: block;" id="formatbar_Buttons"&gt;&lt;span class="down" style="display: block;" id="formatbar_CreateLink" title="Enlace" onmouseover="ButtonHoverOn(this);" onmouseout="ButtonHoverOff(this);" onmouseup="" onmousedown="CheckFormatting(event);FormatbarButton('richeditorframe', this, 8);ButtonMouseDown(this);"&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-8229038484173516365?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/8229038484173516365/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=8229038484173516365' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/8229038484173516365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/8229038484173516365'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2008/02/desarrollo-web-con-zope.html' title='Desarrollo web con zope'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-5134629122136003717</id><published>2007-11-23T06:16:00.000-08:00</published><updated>2007-11-23T06:26:16.879-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><category scheme='http://www.blogger.com/atom/ns#' term='Funcional'/><title type='text'>Sobre Monadas, monoides y afines</title><content type='html'>Brian Beckman ofrece un vídeo orientado a los programadores donde explica que es una monada:&lt;br /&gt;&lt;br /&gt;http://channel9.msdn.com/ShowPost.aspx?PostID=358968#358968&lt;br /&gt;&lt;br /&gt;Otra serie de vídeos interesantes sobre el tópico, aunque mas orientados hacia la parte matemática pueden verse  en el canal de YouTube &lt;a href="http://www.youtube.com/user/TheCatsters"&gt;"The Catsters"&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-5134629122136003717?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/5134629122136003717/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=5134629122136003717' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/5134629122136003717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/5134629122136003717'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/11/sobre-monadas-monoides-y-afines.html' title='Sobre Monadas, monoides y afines'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-3554184818274606436</id><published>2007-07-31T05:53:00.000-07:00</published><updated>2007-07-31T06:36:44.356-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><category scheme='http://www.blogger.com/atom/ns#' term='Funcional'/><title type='text'>Como no aprender sobre recursividad</title><content type='html'>A mediados de los 80s descubrí el fascinante mundo de la recursión gracias al lenguaje LOGO. LOGO es un lipsoide con excelente soporte gráfico, por lo que nada mas natural que combinar gráficos y recursión para generar &lt;a href="http://en.wikipedia.org/wiki/Fractal"&gt;fractales&lt;/a&gt; como el &lt;a href="http://en.wikipedia.org/wiki/Koch_snowflake"&gt;copo de nieve&lt;/a&gt;. Desgraciadamente la fuente de la que aprendí no era muy buena es ese tópico en particular. Los ingredientes en una función recursiva son:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Un segmento de código que evite la recursión infinita&lt;/li&gt;&lt;li&gt;Un segmento de código que haga el trabajo&lt;/li&gt;&lt;li&gt;Un segmento de código que reinvoque la función&lt;/li&gt;&lt;/ul&gt;Con esta receta me encaminé a implementar mis propias funciones recursivas como la &lt;a href="http://en.wikipedia.org/wiki/Hilbert_curve"&gt;curva de Hilbert&lt;/a&gt;. Pasar de la teoría a la práctica es bastante difícil, sobre todo cuando no se tiene computador, mucho menos una versión de LOGO a la mano. Así que tenía que hacer los algoritmos en papel, hacer una corrida en frío, ejecutándolos con lápiz y escuadra. Pero la mayor dificultad estaba en dar con el algoritmo recursivo correcto, básicamente por ensayo y error.&lt;br /&gt;&lt;br /&gt;Cuando pasé de los gráficos a las estructuras de datos, la vieja receta aprendida se mostró igualmente ineficiente. La recursión era para mí un arte y no una ciencia. Eso hasta que fui enseñado correctamente, gracias a un libro de &lt;a href="http://www.amazon.com/ANSI-Common-LISP-Paul-Graham/dp/0133708756"&gt;Paul Graham&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;La belleza de las funciones recursivas se muestra en todo su esplendor con las estructuras de datos recursivas. Cuando se define una estructura de datos recursiva se da una receta para crear nuevos valores en base a valores previos. Por ejemplo, para definir una lista en Haskell:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;data Lista a = Nulo | Cons a (Lista a)&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Esta expresión dice que una lista de un tipo "a" es o bien el elemento especial "Nulo" o la unión ("Cons") de un elemento de tipo "a" con una lista de tipo "a" (desde luego, Haskell ya tiene definido su propio tipo para las listas, con una notación mas suscinta. Sin embargo, para fines didácticos esta definición es mas conveniente).&lt;br /&gt;&lt;br /&gt;Aquí es donde se evidencia el poder de las funciones recursivas. Para definir una función recursiva sobre el tipo de datos Lista a, solo hay que considerar que se debe hacer para cada una de las partes que conforman su definición. Donde aparezca "Lista a" cabe esperarse que haya un llamado recursivo. Por ejemplo, para obtener la longitud de una lista:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;longitud Nulo = 0&lt;br /&gt;longitud Cons a b = 1 + longitud b&lt;/blockquote&gt;&lt;br /&gt;Es esta simetría entre la forma de la estructura de datos y la función recursiva lo que facilita el trabajo al programador.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-3554184818274606436?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/3554184818274606436/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=3554184818274606436' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/3554184818274606436'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/3554184818274606436'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/07/como-no-aprender-sobre-recursividad.html' title='Como no aprender sobre recursividad'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-7084609063387418345</id><published>2007-07-02T08:48:00.000-07:00</published><updated>2007-07-02T08:56:18.884-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>Haskell como herramienta para los matematicos</title><content type='html'>Una interesante &lt;a href="http://haskell.org/haskellwiki/Blog_articles/Mathematics#Haskell_for_mathematics"&gt;página&lt;/a&gt; en el sitio de haskell resume las ventajas que ofrece un lenguaje funcional fuertemente tipificado para el aprendizaje, estudio y juego con la matemática.&lt;br /&gt;&lt;br /&gt;Otros lenguajes, como &lt;a href="http://www.lambdassociates.org/aboutqi.htm"&gt;Qi&lt;/a&gt;, pueden ofrecer estas mismas ventajas con el añadido de ser derivados de Lisp y por lo tanto, conceptualmente mas austeros.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-7084609063387418345?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/7084609063387418345/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=7084609063387418345' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/7084609063387418345'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/7084609063387418345'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/07/haskell-como-herramienta-para-los.html' title='Haskell como herramienta para los matematicos'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-2452405647666370286</id><published>2007-06-20T08:09:00.000-07:00</published><updated>2007-06-20T08:20:07.584-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>Python 3000</title><content type='html'>&lt;pre&gt;Recientemente, &lt;span class="as"&gt;Guido van Rossum concretó mas detalles sobre el futuro Python 3000:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=208549" target="_blank"&gt;http://www.artima.com/weblogs/viewpost.jsp?thread=208549&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Es de particular relevancia:&lt;br /&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;El Viejo sistema de Clases desaparecerá.&lt;/li&gt;&lt;li&gt;Mayor coherencia en la librería estándar.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;La compatibilidad con versiones previas no es un objetivo.&lt;/li&gt;&lt;/ul&gt;Python ha seguido una evolución interesante, pasando a ser un "verdadero" lenguaje orientado a objetos al tiempo que ha visto incrementado el rango de funcionalidades que ofrece "out of the box". Sin embargo, su inicio modesto y la colaboración de centenares de personas en la elaboración de las librerías, de alguna forma ha causado que el lenguaje haya dejado de ser tan simple y elegante como lo era en un principio.&lt;br /&gt;&lt;br /&gt;La mayor (tal vez la única?) envidia que sienten los pythonistas ante, digamos, Java, es que sus librerías lucen estandarizadas. Esto en el sentido que todas cumplen con una convención de nombres y denominaciones que facilita su aprendizaje (podemos criticar todo lo que queramos el &lt;span style="font-style: italic;"&gt;diseño&lt;/span&gt;, sentido o necesidad de muchas librerías de Java, pero al menos son consistentes en sus APIs).&lt;br /&gt;&lt;br /&gt;Esta es una excelente oportunidad para que este magnifico lenguaje, que ya ha sentido las tensiones entre el crecimiento y la elegancia, recobre la consistencia interna que a tantos de nosotros enamoró.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-2452405647666370286?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/2452405647666370286/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=2452405647666370286' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/2452405647666370286'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/2452405647666370286'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/06/python-3000.html' title='Python 3000'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-7322874116225287833</id><published>2007-05-28T07:09:00.000-07:00</published><updated>2007-05-28T07:38:22.803-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>La Perfecta Maquina Virtual</title><content type='html'>La idea de una maquina virtual no es nueva. Antes que C#, antes que Java, incluso antes que el microprocesador, ya habían &lt;a href="http://en.wikipedia.org/wiki/VM_%28operating_system%29"&gt;maquinas virtuales&lt;/a&gt; operando en los "mini" computadores de la época.&lt;br /&gt;&lt;br /&gt;De hecho, el término "maquina virtual" se ha ampliado haciéndose cada vez mas difuso. Al principio, las maquinas virtuales implicaban un soporte de hardware que permitía que varios sistemas operativos corrieran independientemente en un equipo.&lt;br /&gt;&lt;br /&gt;Las maquinas virtuales al estilo Java y .Net son las que han traído el concepto al foco de atención de la mayoría de los programadores en los tiempos recientes. Este tipo de maquinas virtuales son "computadores implementados en software" que corren sobre el sistema operativo anfitrión y que se usan para ejecutar las aplicaciones.&lt;br /&gt;&lt;br /&gt;Otro enfoque es el del sistema operativo. La idea es que, dado que la principal función del sistema operativo es hacer una abstracción del hardware sobre el que este corre, el propio sistema operativo constituye una maquina virtual. De hecho, muchas veces los núcleos de los sistemas operativos son llamados maquinas virtuales.&lt;br /&gt;&lt;br /&gt;Y es aquí donde viene la atractiva idea de &lt;a href="http://www.openlina.com/description.html"&gt;Lina&lt;/a&gt;. Si una maquina virtual puede ser tanto una aplicación como el núcleo de un sistema operativo, por que no aprovechar uno de los sistemas operativos libres mas populares y exitosos del mundo? Ese es el concepto tras OpenLina: correr el núcleo de linux sobre windows,  OSX y el propio Linux. Las librerías de soporte mapearan llamadas estándar de lina a servicios del sistema anfitrión. Las aplicaciones de lina podrán correr así en cualquier plataforma. Si bien esto es poco mas o menos lo que hace Java, por ejemplo, la novedad esta en que la maquina virtual de lina (el núcleo de linux) es una pieza de software muy madura y excelentemente soportada y con librerías estandarizadas.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-7322874116225287833?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/7322874116225287833/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=7322874116225287833' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/7322874116225287833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/7322874116225287833'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/05/la-perfecta-maquina-virtual.html' title='La Perfecta Maquina Virtual'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-7805648412392750869</id><published>2007-05-07T12:31:00.000-07:00</published><updated>2007-05-07T13:33:28.965-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><category scheme='http://www.blogger.com/atom/ns#' term='Funcional'/><title type='text'>Diversión con Monadas</title><content type='html'>Para el programdor en Haskell, pocos conceptos son tan dificiles de aprehender como las monadas. Existen &lt;a href="http://del.icio.us/popular/monad"&gt;infinidad&lt;/a&gt; de tutoriales sobre el tema y al parecer estos no son suficientes. Su origen en la teoría de tipos y su nombre atemorizante intimidan, al punto que uno de los pilares de Haskell ha comentado que tal vez deban rebaustizarse como las monadas con el titulo de las "cosas difusas y calidas" (warm fuzzy things) con el objeto de hacerlas mas amistosas.&lt;br /&gt;&lt;br /&gt;Hay dos elementos que contribuyen a la confusión del recien llegado con las monadas. El primero tiene que ver con su uso especifico para contener los efectos colaterales, es decir la programación no funcional, en particular el sistema de entrada/salida. Esto deja al recien iniciado preguntandose si monadas es sinonimo de I/O.&lt;br /&gt;&lt;br /&gt;El segundo elemento que contribuye a la confusión inicial es un menejo del tema desligado de las implicaciones practicas. En Haskell &lt;a href="http://www.haskell.org/all_about_monads/html/class.html#monad"&gt;una monada es una clase&lt;/a&gt;. Para convertir un tipo dado en una monada hay que implementar las funciones definidas en dicha clase y dichas funciones deben cumplir ciertas de reglas. Un importante conjunto de librerías de Haskell implementan monadas. Todo eso muy bien, pero &lt;span style="font-weight: bold;"&gt;¿por que dichas librerías son implementadas así y no otras? ¿Cuando debería &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;un programador desarrollar sus propias monadas?¿Como implemento mi monada?¿Como garantizar que las monadas creadas cumplan con dichas reglas?¿Que pasa si no cumplen con las mismas?&lt;/span&gt; Esas son preguntas mas interesantes.&lt;br /&gt;&lt;br /&gt;La mejor forma de aprender el significado de las monadas es entender cuando tú como programador deberias implementar una solución basada en monadas. Una vez entendido esto, resulta fácil entender las librerías y saber por que el sistema de I/O de Haskell y el código que produce efectos colaterales es implementado de esa forma. En ese sentido, no hay mejor tutorial que &lt;a href="http://sigfpe.blogspot.com/2006/08/you-could-have-invented-monads-and.html"&gt;"Tu pudiste haber inventado las monadas! (y tal vez ya lo hiciste)"&lt;/a&gt; por sigfpe.&lt;br /&gt;&lt;br /&gt;La idea de sigfpe es simple abordar las monadas desde un punto de vista utilitario. ¿Para que sirven?. ¿Que problema resuelven?. Él hace un trabajo insuperable, por lo que aquí me limitare a reexpresar la conclusión a la que llega:&lt;br /&gt;&lt;br /&gt;Desde el punto de vista del programador, las monadas son la extensión natural a los functores. &lt;a href="http://st.dinuncio.web.ve/2007/02/diversin-con-functores.html"&gt;Como ya vimos&lt;/a&gt; los functores son una forma de mapear las funciones que operan sobre tipos "simples" a funciones que operan sobre tipos "compuestos".&lt;br /&gt; Lo que las monadas permiten es componer funciones cuyo dominio es el tipo "simple" y su rango es el tipo "compuesto" entre si. Sencillo, no?&lt;br /&gt;&lt;br /&gt;Eso es todo lo que significa el operador "bind" de la clase Monad:&lt;span style="font-family: monospace;"&gt;   &lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;&lt;blockquote&gt;(&gt;&gt;=)  :: m a -&gt; (a -&gt; m b) -&gt; m b&lt;/blockquote&gt;&lt;/span&gt;El programador ha desarrollado bastante tiempo creando funciones que toman argumentos simples y devuelven argumentos complejos, como por ejemplo a -&gt; m b, b -&gt; m c y ahora desea combinar esas funciones. Pero como la primera devuelve un valor compuesto (m b) y la segunda requiere un valor simple (b), necesita alguna forma de "sacar" (b) de (m b) para introducirla en la segunda función. Eso responde todas las preguntas planteadas sobre las monadas, como se vera a continuación.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Cuando debería un programdor desarrollar sus propias monadas?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Cuando desarrolla su propio tipo "compuesto" y necesita componer funciones del tipo "simple" hacia el tipo "compuesto".&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Por que ciertas librerías en Haskell estan implementadas como monadas?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Porque dichas librerías implican tipos "compuestos" y funciones que devuelven este tipo de valores y que es útil componer. Así por ejemplo, la librería IO no trabaja diretamente sobre enteros, reales y caracteres sino sobre tipos derivados {tipos que contienen de forma oculta el estado del universo y que podriamos sentirnos tentados a representar como (entero, mundo), (real, mundo) y (caracter, mundo)}.&lt;br /&gt;Una revision a las librerías que son implementadas como monadas arroja esa constante: tipos compuestos involucrados (a veces habilmente ocultos) y funciones sobre ellos que es conveniente componer.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;¿Como implemento mi monada?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Al crear el tipo compuesto; al necesitar componer las fuciones el programador ya sabe como implementar la monada. Sin un ejemplo en esta pagina puede sonar bastante abstracto, pero el tutorial de sigfpe ofrece suficientes ejemplos y ejercicios. Basta decir que la naturaleza misma del tipo compuesto y su uso deseado sirve para definir la monada.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;¿Como garantizar que las monadas creadas cumplan con las reglas de las monadas?&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;Uno de los temores del programador recien iniciado a las monadas y que las aprendió por su definición es temer que su implementación de una monada sea invalida. Esto ocurre cuando se trata de imponer el concepto no bien internalizado de una monada sobre un problema. En el momento en que el programador se da cuenta que implementar una monada es implementar la composicion entre funciones de una forma que tenga sentido para el tipo "compuesto", el temor a implementar incorrectamente una monada desaparece.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;¿Pero que pasa si mi monada no cumplen con la leyes?&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;Esa situación es perfectamente posible y tiene un término técnico que la describe, se le denomina &lt;span style="font-style: italic;"&gt;bug&lt;/span&gt;. una monada que no cumple con sus leyes es, desde luego, inútil. Pero ello significa simplemente que tú como progrmador cometiste un error en la función que crea un valor "compuesto" a partir de un valor "simple", o que la función de composición no esta correctamente definida. Es un bug como cualquier otro, no hay nada místico en ello.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-7805648412392750869?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/7805648412392750869/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=7805648412392750869' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/7805648412392750869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/7805648412392750869'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/05/diversin-con-monadas.html' title='Diversión con Monadas'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-6426010281787594840</id><published>2007-04-11T07:17:00.000-07:00</published><updated>2007-04-11T08:56:55.071-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><category scheme='http://www.blogger.com/atom/ns#' term='Funcional'/><title type='text'>Sobre los Tipos de Datos Algebraicos y la Abstracción</title><content type='html'>Desde el comienzo de la computación electrónica ha habido dos campos en el desarrollo de los lenguajes de programación: los que buscan velocidad y los que  buscan expresividad. Los primeros se caracterizan por su poco nivel de abstracción. Las características del equipo donde corren son visibles al programador y este, en su trabajo, debe preocuparse por ellos. El ejemplo clásico es el lenguaje C.&lt;br /&gt;&lt;br /&gt;El otro tipo de lenguajes, representados por scheme, lisp, haskell y varios lenguajes de scripts, busca la abstracción. El programador debe preocuparse por expresar el problema en los términos mas cercanos al mismo, sin hacer consideraciones o concesiones a la plataforma.&lt;br /&gt;&lt;br /&gt;Para alcanzar tan loable objetivo, pocas herramientas son tan útiles  como los &lt;a href="http://en.wikipedia.org/wiki/Algebraic_data_type"&gt;Tipos de Datos Algebraicos o ADT&lt;/a&gt;, por sus siglas en ingles. La idea de los tipos algebraicos es permitirle al programador definir nuevos valores primitivos y a partir de ellos generar nuevos tipos, combinando los valores, bien sea por medio de la unión de conjuntos o su producto.&lt;br /&gt;&lt;br /&gt;Un ejemplo permitirá mostrar el valor de los ADT como medio de abstracción, comparando la solución a un problema en C, Haskell y, por diversion, BASIC.&lt;br /&gt;&lt;br /&gt;Si bien BASIC sería bajo los estándares actuales un lenguaje de script, y por lo tanto mas abstracto, me referiré en cambio a las primeras versiones de BASIC, antes de Visual Basic o Turbo BASIC; un lenguaje mas cercano a la idea original, para correr en una maquina con menores recursos. Hablemos del BASIC que corría en un equipo como el Commode 64 o el Sinclair ZX Spectrum.&lt;br /&gt;&lt;br /&gt;El problema en cuestión es extremadamente simple: representar un mazo de cartas. Cada carta tiene una pinta que puede ser corazón, pica, diamante o trébol y un "numero" que puede ser los números del 2 al 10, las letras "A", "J", "Q" o "K".&lt;br /&gt;&lt;br /&gt;En un lenguaje de programación contemporáneo una carta podría ser representada por un registro o un objeto, de acuerdo al paradigma para el cual el lenguaje este optimizado. En el BASIC que tengo en mente, conceptos como registros y objetos son términos muy avanzados. Como se representa un registro en tal BASIC? Fácil: con variables separadas, siendo responsabilidad del programador mantener en su cabeza la asociación entre tales variables. Así la J de trébol podría representarse como:&lt;br /&gt;&lt;blockquote&gt;10 c1p = 4&lt;br /&gt;20 c1n = 11&lt;/blockquote&gt;El 10 y el 20 son los "números de linea". Cada linea del programa debía tener un numero, el cual era usado como medio para acceder a la misma por los primitivos editores que era menester hacer caber en 8KB de memoria o menos.&lt;br /&gt;&lt;br /&gt;Sin embargo esta solución es suboptima. Los números mágicos 4 y 11 son una mala señal. En un lenguaje cuyos únicos tipos son los números reales, los arreglos y las cadenas de caracteres es poco lo que se puede hacer, mas allá de representar las pintas y los "numeros" especiales de las cartas con constantes:&lt;br /&gt;&lt;blockquote&gt;10 c1p = 4&lt;br /&gt;20 c1n = 11&lt;br /&gt;10 CPCORAZON = 0&lt;br /&gt;20 CPPICA = 1&lt;br /&gt;30 CPDIAMANTE = 2&lt;br /&gt;40 CPTREBOL = 3&lt;br /&gt;50 CNA = 1&lt;br /&gt;60 CNJ = 11&lt;br /&gt;70 CNQ = 12&lt;br /&gt;80 CNK = 13&lt;br /&gt;...&lt;br /&gt;500 c1p = CPTREBOL&lt;br /&gt;510 c1n = CNJ&lt;/blockquote&gt;&lt;br /&gt;Mencione que la mayoría de los BASIC de esa época eran insensibles a las mayúsculas y minúsculas y que tenían un limite en el tamaño del nombre de las variables?&lt;br /&gt;&lt;br /&gt;Ahora, para representar a un mazo de cartas, se necesita un arreglo... mejor dicho dos arreglos. De nuevo, hay que mantener separados las pintas de los números y hacer la asociación mental durante la escritura del programa.&lt;br /&gt;&lt;blockquote&gt;590 rem el comando dim crea un arreglo&lt;br /&gt;600 dim mp(52)&lt;br /&gt;610 dim mn(52)&lt;br /&gt;&lt;/blockquote&gt;Para inicializar los arreglos, es útil el hecho de que la representación elegida para las pintas y los "números" son ambas numéricas, y como cada carta es diferente puede establecerse una correspondencia entre los naturales y estas:&lt;br /&gt;&lt;blockquote&gt;700 for x = 0 to 51&lt;br /&gt;705 rem cada 13 cartas cambia la pinta&lt;br /&gt;710 mp(x) = int(x/13)&lt;br /&gt;720 mn(x) = (x mod 13) + 1&lt;br /&gt;730 next x&lt;br /&gt;&lt;/blockquote&gt;La solución en BASIC es engorrosa. Parte del problema no esta reflejado directamente en el programa, sino que debe ser sobreentendido, en particular la necesidad de usar arreglos diferentes para una sola entidad, o la representación numérica de entes como la pinta y el "numero" de la carta.&lt;br /&gt;&lt;br /&gt;La solución en C es mas avanzada. El C nos ofrece ENUMs que es una forma básica de representar tipos de datos no númericos.&lt;br /&gt;&lt;blockquote&gt; enum  pinta         {Corazon, Pica, Diamante, Trebol};&lt;br /&gt;enum numero  {As, Dos, Tres, Cuatro, Cinco,&lt;br /&gt;                         Seis, Siete, Ocho, Nueve, Diez,&lt;br /&gt;                                                Jack, Queen, King};&lt;/blockquote&gt;Tambien permite definir estructuras (registros), con lo que se solventa el problema de mas de una variable para un solo ente.&lt;br /&gt;&lt;blockquote&gt;struct  { enum   pinta pinta;&lt;br /&gt;             enum   numero numero; } carta;&lt;/blockquote&gt;Una solución mucho mas elegante que la elaborada en BASIC, pero no mucho mas abstracta. Un enum es poco mas o menos que un conjunto de constantes con valores enteros creados automáticamente. En nuestro caso, &lt;span style="font-style: italic;"&gt;Corazon&lt;/span&gt; es solo una forma de decir 0 y &lt;span style="font-style: italic;"&gt;Trebol&lt;/span&gt; es 3. De hecho, una variable declarada como enum puede contener cualquier valor entero, mas allá de los cuatro valores permitidos.&lt;br /&gt;&lt;br /&gt;Una estructura tiene también una representación de bajo nivel que puede ser accedida por el programador. Para un compilador especifico el "numero" de una carta puede estar almacenado cuatro bytes después de su pinta, por lo que obteniendo la dirección de esta, se puede modificar aquella.&lt;br /&gt;&lt;br /&gt;En resumen, se ha ganado algo de abstracción, pero solo en la forma. Si el programador se compromete a no efectuar ninguna operación sobre las estructuras básicas subyacentes, es probable que todo le salga bien...&lt;br /&gt;&lt;br /&gt;Veamos ahora la solución en Haskell, el único de los lenguajes mencionados en este articulo que tiene ADT. Primero creamos un nuevo tipo de datos algebraico para la pinta y el "numero" de la carta:&lt;br /&gt;&lt;blockquote&gt;data Pinta = Corazon | Pica | Diamante | Trebol&lt;br /&gt; data Numero = As | Dos | Tres | Cuatro | Cinco&lt;br /&gt;                        | Seis | Siete | Ocho | Nueve | Diez&lt;br /&gt;                        | Jack | Queen | King&lt;/blockquote&gt;&lt;br /&gt;Y luego creamos otro tipo algebraico con el producto cartesiano de los dos antes definidos:&lt;br /&gt;&lt;blockquote&gt;data Carta = Carta Numero Pinta&lt;/blockquote&gt;&lt;br /&gt;Igual a lo expresado en C? Solo superficialmente. &lt;span style="font-style: italic;"&gt;Pinta&lt;/span&gt; es un nuevo tipo de datos, no un entero. Su representación interna por el compilador es desconocida. Tal vez sería una buena adivinanza suponer que es representado por un entero de un byte. Pero adivinar sería fútil, ya que el saberlo es irrelevante: la única forma de operar sobre un tipo algebraico es con las operaciones explícitamente definidas por el programador. Lo mismo ocurre con el tipo &lt;span style="font-style: italic;"&gt;Carta&lt;/span&gt;. Si, de seguro durante la compilación nuestro tipo algebraico se convierte en una estructura equivalente a la del C, pero eso es un asunto entre el compilador y la CPU. Para el programador es un ítem único e indivisible.&lt;br /&gt;&lt;br /&gt;También esta el aspecto sicológico. En el caso del C el programador esta definiendo un layout de memoria y unas constantes enteras. En Haskell, el programador esta declarando que una carta es representada por un "numero" y una pinta, y que la pinta puede tomar solo estos valores y que un "numero" en este contexto son tales otros.&lt;br /&gt;&lt;br /&gt;Este aspecto sicológico es un subproducto de la mayor capacidad de abstracción del lenguaje, y es una de las mas importantes contribuciones para el programador.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-6426010281787594840?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/6426010281787594840/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=6426010281787594840' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/6426010281787594840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/6426010281787594840'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/04/sobre-los-tipos-de-datos-algebraicos-y.html' title='Sobre los Tipos de Datos Algebraicos y la Abstracción'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-1723882715143724996</id><published>2007-03-16T06:05:00.000-07:00</published><updated>2007-03-16T06:30:04.525-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>Saber decir "No"</title><content type='html'>Que hace a un lenguaje diferente de otro? En el caso particular de los lenguajes de script imperativos, es cada vez mas amplia la lista de características compartidas: las estructuras de control "estructuradas", las listas, los diccionarios, las funciones como ciudadanos de primera clase...&lt;br /&gt;&lt;br /&gt;Y sin embargo, programar en Ruby sigue siendo diferente a programar en TCL; programar en python tiene un sabor distinto a hacerlo en perl. Entonces, cual es la diferencia? La raíz en la diferenciación de los lenguajes esta en su filosofía, la idea que guía a sus desarrolladores a decidir que características entran en el lenguaje y como lo hacen.&lt;br /&gt;&lt;br /&gt;Paul Graham tiene un &lt;a href="http://www.paulgraham.com/fix.html"&gt;articulo&lt;/a&gt; interesante al respecto en donde lista los lenguajes de acuerdo al problema que pretenden resolver. Esta puede ser una primera guía sobre la filosofía de los desarrolladores.&lt;br /&gt;&lt;br /&gt;En el caso de python, su mantra esta explicado en el 'import this' (pruebe importar el modulo &lt;span style="font-weight: bold;"&gt;this&lt;/span&gt; en un interprete en python). Los dos preceptos fundamentales en el python son la legibilidad y la simplicidad. El lenguaje procura no interponerse en el camino del programador, de manera que el pueda expresar de forma clara sus intensiones. Para ello es fundamental ser sucinto en los conceptos. Por esta razon el punto 13 del zen de python es: "Debe haber una forma obvia de hacerlo --y preferiblemente solo una".&lt;br /&gt;&lt;br /&gt;Así, lo que distingue al python es que su filtro para nuevas caracteristicas es: ayuda la característica a expresar los algoritmos de forma mas clara? mas concisa? menos redundante? Y ello lo ha logrado -sorprendentemente, para algunos- sabiendo decir "no" a ciertas funcionalidades.&lt;br /&gt;&lt;br /&gt;Después de todo, expresividad no es poder decir una cosa de mil maneras distintas; es poder decir cualquier cosa, al menos de una manera.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-1723882715143724996?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/1723882715143724996/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=1723882715143724996' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/1723882715143724996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/1723882715143724996'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/03/saber-decir-no.html' title='Saber decir &quot;No&quot;'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-4548993764180747454</id><published>2007-02-08T06:25:00.000-08:00</published><updated>2007-02-09T08:07:38.138-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><category scheme='http://www.blogger.com/atom/ns#' term='Funcional'/><title type='text'>Diversión con functores</title><content type='html'>Despues de programar durante algún tiempo, es común encontrarse repitiendo una y otra vez las mismas soluciones, con ligeras variantes. Es esta ha originado todas las innovaciones en el campo, desde la creación de subrutinas hasta los macros.&lt;br /&gt;&lt;br /&gt;Una de estas situaciones se presenta cuando se tiene una funcion que convierte datos del tipo A al tipo B y se la desea transformar en una nueva función que opere sobre un tipo derivado de A para convertirlo en un tipo derivado (en una manera equivalente) de B.&lt;br /&gt;&lt;br /&gt;La &lt;a href="http://en.wikipedia.org/wiki/Functor"&gt;definición de functores&lt;/a&gt; es:&lt;br /&gt;&lt;br /&gt;Dadas dos categorías C y D, un functor F de C a D es un mapeo que:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Asocia a cada elemento X de C un elemento F(X) de D&lt;/li&gt;&lt;li&gt;Asocia a cada funcion f: X -&gt; Y de C otra F(f): F(X) -&gt; F(Y)&lt;/li&gt;&lt;/ul&gt;De manera tal que&lt;br /&gt;&lt;ul&gt;&lt;li&gt;F(IDx) = ID(Fx)&lt;/li&gt;&lt;li&gt;F(f o g) = F(f) o F(g)&lt;/li&gt;&lt;/ul&gt;Desde el punto de vista programatico, un functor esta formado por dos funciones: la primera convierte tipos "simple" en tipos "complejos" y la segunda convierte funciones cuyo dominio y rango son tipos "simples" a otras funciones, en algún sentido equivalentes, pero cuyo dominio y rango son tipos "complejos". De esta forma, si has programado una función que convierta manzanas en compotas, aplicando un functor tienes automaticamente una funcion que convierta cajas de manzanas en cajas de compotas o camiones de manzanas en camiones de compotas.&lt;br /&gt;&lt;br /&gt;Un ejemplo practico es el functor cuyo rango son las listas. La categoría C sería el conjunto de todos los tipos que son susceptibles de ser contenidos dentro de listas (enteros, reales, complejos, caracteres, incluso listas, ...). La categoría D esta formada por las listas de los tipos en la categoría C (listas de enteros, listas de reales, listas de complejos, listas de caracteres, listas de listas, ...).&lt;br /&gt;&lt;br /&gt;Para definir dicho functor, necesitamos una función que convierta elementos de los tipos en C a elementos en los tipos en D. En este caso la función es simple, solo necesita crear una lista con ese unico elemeto. El otro elemento necesario es una función que convierta una funcion del tipo X -&gt; Y en una funcion del tipo [X] -&gt; [Y]. En &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Haskell&lt;/span&gt; esta función se denomina &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;map&lt;/span&gt;, y su definición es:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;map&lt;/span&gt; [] f = []&lt;br /&gt;&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;map&lt;/span&gt; x:&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;xs&lt;/span&gt; = (f x) : (&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;map&lt;/span&gt; &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;xs&lt;/span&gt;)&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Eso es todo. Al definir &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;map&lt;/span&gt;, se ha solucionado de una vez por todas el problema de &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;mapear&lt;/span&gt; funciones hacia la categoría de las listas. Desde luego, cada categoría distinta requiere un &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;mapeo&lt;/span&gt; distinto. Normalmente la primera parte del &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;mapeo&lt;/span&gt; es el constructor de tipos y la segunda recibe como nombre genérico "&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;fmap&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;La belleza de la programación funcional en lenguajes como &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;Haskell&lt;/span&gt; es la simplicidad con la que se implementan conceptos como los &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;functores&lt;/span&gt;. &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;Lengajes&lt;/span&gt; imperativos como Java poseen todo lo necesario para crear &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;functores&lt;/span&gt;: funciones que &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;mapean&lt;/span&gt; tipos a otros tipos (&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;generics&lt;/span&gt; en el lenguaje de java), funciones como ciudadanos de primera clase (en java, clases) e interfaces. Sin embargo, su implementación es mucho mas verbosa.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-4548993764180747454?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/4548993764180747454/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=4548993764180747454' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/4548993764180747454'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/4548993764180747454'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/02/diversin-con-functores.html' title='Diversión con functores'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-1659246417390603520</id><published>2007-02-07T06:46:00.000-08:00</published><updated>2007-02-07T16:43:06.424-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>El olor de la sangre</title><content type='html'>Recientemente he estado implementando un protocolo de comunicación para un dispositivo embebido. Dada la naturaleza de la plataforma, el lenguaje de programación elegido fue C.&lt;br /&gt;&lt;br /&gt;Así que comencé a programar: a preocuparme por el manejo de memoria, a acceder a los elementos de un arreglo a través de índices que yo mismo me veía obligado a incrementar, a codificar mis estructuras de datos utilizando números en vez tipos de datos algebraicos.&lt;br /&gt;&lt;br /&gt;Conforme iba retrocediendo en la escala evolutiva de los lenguajes  me ocurrió algo curioso... algo solo comparable a la involución que sufrieron los protagonistas de "El señor de las moscas". A medida que me acercaba cada vez mas al ensamblador despertaba en mi algo atabico, casi salvaje... Programar la maquina desnuda, sin la ayuda de poderosos conceptos fue una experiencia intoxicante... casi lo mismo que debían sentir nuestros ancestros al cazar bisontes solo con piedras y flechas... al percibir el olor de la sangre de la presa cazada...&lt;br /&gt;&lt;br /&gt;Desde luego, la aplicación era lo suficientemente pequeña como para que el lado &lt;a href="http://st.dinuncio.web.ve/2007/01/el-mal-c.html"&gt;oscuro&lt;/a&gt; del c no se mostrara. De haber sido mas grande la aplicación, los problemas con el manejo de memoria, el tedio de la escritura de código boilerplate, la molestia de tener a cada paso que indicar lo obvio me habría frustrado. Al igual que un citadino transportado a los albores de nuestra especie se habría aburrido esperando por la presa, hambriento, exasperado por los mosquitos y molesto por las inclemencias del tiempo.&lt;br /&gt;&lt;br /&gt;Es que el olor de la sangre llama, pero no tanto...&lt;br /&gt;&lt;a href="http://st.dinuncio.web.ve/2007/01/el-mal-c.html"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-1659246417390603520?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/1659246417390603520/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=1659246417390603520' title='1 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/1659246417390603520'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/1659246417390603520'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/02/el-olor-de-la-sangre.html' title='El olor de la sangre'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-2353461766645632939</id><published>2007-02-04T06:49:00.000-08:00</published><updated>2007-02-04T07:42:40.261-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><category scheme='http://www.blogger.com/atom/ns#' term='Funcional'/><title type='text'>Un abreboca al poder de la programación funcional</title><content type='html'>Una de las razones por la cual la programación funcional es considerada poderosa es por la facilidad con la que se puede derivar nuevo código a partir del ya existente. Por ejemplo, una de las tareas mas comunes durante el desarrollo de programas es operar sobre una colección de datos, bien sea para generar una nueva colección, modificar la ya existente o generar una estructura nueva derivada de esta.&lt;br /&gt;&lt;br /&gt;Así, si quisieramos la sumatoria de los valores en un arreglo numérico el código (en python) seria:&lt;br /&gt;&lt;br /&gt;  suma = 0&lt;br /&gt;  for x in arreglo :&lt;br /&gt;    suma += x&lt;br /&gt;&lt;br /&gt;Para elevar al cuadrado los componentes de un arreglo, la solución que implementaría un programador de C escribiendo python seria:&lt;br /&gt;&lt;br /&gt;  for i in len(arreglo) :&lt;br /&gt;    arreglo[i] = arreglo[i]**2&lt;br /&gt;&lt;br /&gt;(python tienen una forma mas elegante de lograrlo, pero es precisamente una forma "prestada" de lenguajes con paradigmas diferentes al imperativo).&lt;br /&gt;&lt;br /&gt;Estos códigos son representativos de las soluciones imperativas: crear un bucle que recorra el arreglo, operando sobre cada elemento para generar el resultado deseado. Un programador de C o Java con algunos años de experiencia habrá escrito lineas semejantes a esas un millar de veces. El problema esta en que precisamente la tarea es tan común que forma un patrón ideal para ser resumido.&lt;br /&gt;&lt;br /&gt;Ahora, como podría aislarse esa solución en un lenguaje como C o Java, de manera que el programador solo tuviera que escribir la parte del problema que cambia (el suma +=x  o el arreglo[i] = arreglo[i]**2)? Dado que la estructura semántica del C y el java están fijadas y no lo permiten directamente, la única posibilidad seria por medio de una librería. La librería implementaría la parte común (el bucle) y recibiría como parámetro un elemento (un objeto en Java o un apuntador a una función en C) que contenga el pedazo de programa que varía.&lt;br /&gt;&lt;br /&gt;Y he allí el problema. Declarar una función en C es mas trabajo que escribir el bucle directamente. Definir una clase en Java que implemente el comportamiento deseado, instanciarla y pasar el objeto a la librería no es una opción: es una penitencia.&lt;br /&gt;&lt;br /&gt;La mayoría de los lenguajes funcionales por otra parte permiten la creación de funciones con un costo mínimo para el programador, razón por la cual hacer una librería con los tipos mas comunes de bucles no solo es viable, sino la forma natural de proceder.&lt;br /&gt;&lt;br /&gt;El primer caso mostrado, la suma de los valores en un arreglo, es de hecho un caso particular de un tipo de bucles llamado fold (también llamado reduce). Este caso se caracteriza por dos elementos: un valor a ser devuelto en caso que el arreglo sea de longitud cero, y una función que tome dos valores y devuelve uno, la cual es usada para "reducir" el arreglo. En nuestro caso, el valor a ser devuelto en caso que el arreglo este vació es cero y la función que reduce el arreglo es la suma.&lt;br /&gt;&lt;br /&gt;Así, expresar ese bucle en python de forma funcional seria&lt;br /&gt;&lt;br /&gt;    reduce(real.__add__, arreglo, 0.0)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En Haskell, uno de los lenguajes mas elegantes, seria&lt;br /&gt;&lt;br /&gt;    foldr (+) 0.0 arreglo&lt;br /&gt;&lt;br /&gt;En ambos casos el significado es el mismo: si el arreglo esta vació, devuelve 0.0, sino suma sus elementos. Si bien este programa puede resultar de mas difícil lectura (sobre todo debido a la costumbre imperativa), también ofrece algunas ventajas:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Es mas conciso&lt;/li&gt;&lt;li&gt;No usa variables temporales&lt;/li&gt;&lt;li&gt;Puede ser manipulado programaticamente&lt;/li&gt;&lt;/ul&gt;El ultimo punto tendrá un impacto gigante en la forma en que programamos en los años venideros. Dado que la función fold aisla las partes que varían en un bucle y homogeniza la estructura, es mas amistosa desde el punto de vista matemático. Si todos los bucles son expresados con fold y otras pocas estructuras semejantes, el código puede ser transformado por un compilador inteligente siguiendo una serie de teoremas, obteniendo un código super-optimizado.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-2353461766645632939?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/2353461766645632939/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=2353461766645632939' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/2353461766645632939'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/2353461766645632939'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/02/un-abreboca-al-poder-de-la-programacin.html' title='Un abreboca al poder de la programación funcional'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-3121941527502949278</id><published>2007-01-25T04:55:00.000-08:00</published><updated>2007-01-25T05:39:49.600-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><category scheme='http://www.blogger.com/atom/ns#' term='Funcional'/><title type='text'>Alternativa al C: O'Caml</title><content type='html'>Cuando se habla de alternativas al C, la mayoría de personas piensa en C++, Objective C o Java. Un candidato mas digno, aunque menos conocido es el lenguaje D. Todas estas opciones tienen algo en común: son lenguajes de computación que sigue el paradigma imperativo.&lt;br /&gt;&lt;br /&gt;Los lenguajes imperativos se caracterizan por los siguientes elementos:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Son dependientes del estado de la computación: Los resultados de los computos dependen de un conjunto de valores almacenados durante la ejecución del programa y que son mutables&lt;/li&gt;&lt;li&gt;El flujo de control debe ser totalmente especificado&lt;/li&gt;&lt;li&gt;El orden de ejecución debe ser totalmente especificado&lt;/li&gt;&lt;/ul&gt;Estas características hacen que los lenguajes imperativos puedan ser traducidos mas directa y eficientemente a lenguaje maquina, pero al costo de forzar en el programador la especificación de la solución a un mayor nivel de detalle. Por eso, cuando se busca velocidad, la mayoría de los programadores están predispuestos a buscar lenguajes imperativos. O al menos así solía ser&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Bienvenidos a O'Caml&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Los lenguajes funcionales por su parte, ofrecen ciertas ventajas al programador:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;No dependen del estado: Esto elimina un conjunto de errores y permite que el código sea mas auditable (de hecho el código puede ser demostrado correcto, en el sentido matemático del término)&lt;/li&gt;&lt;li&gt;Composición de programas: Pequeños segmentos de programas pueden ser combinados de manera sencilla, permitiendo la generación de código complejo expresado sucintamente&lt;/li&gt;&lt;li&gt;El flujo de control y/o el orden de ejecución no necesita ser indicado explícitamente&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;O'Caml es una interesante encarnación de los lenguajes funcionales. Ofrece todas las ventajas descritas (con la excepción del orden de ejecución, el cual sigue siendo explicito). Además, permite programar en otros paradigmas como el imperativo o el orientado a objetos. Agreguesele a ello su robusto sistemas de tipos, el cual permite detectar muchos errores en tiempo de compilación y generar un código super-optimizado.&lt;br /&gt;&lt;br /&gt;Adicionalmente, O'Caml parece haberse trazado una meta poco común para los lenguajes funcionales: competir en el terreno de los lenguajes imperativos. Así, O'Caml ofrece librerías para la programación bajo UNIX, depuradores, profilers...&lt;br /&gt;&lt;br /&gt;Esto hace del O'Caml uno de los lenguajes mas interesantes y &lt;a href="http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&amp;lang=all"&gt;rápidos&lt;/a&gt;  del vecindario [1], apto incluso para la programación de bajo nivel. De hecho, mientras escribía la entrada respectiva al lenguaje de programación D, para familiarizarme con el, decidí implementar el programa supervise de Dan Berstein. Pues, para mi sorpresa resultó mas directo hacerlo en O'Caml que en D, debido al mejor soporte de las librerías del sistema  (el D es facílmente extensible también; no se trata de una crítica al lenguaje D, sino un reconocimiento a las librerías estándares de O'Caml)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;[1] Si, si. Son micro-benchmarks. Si, si. Estas pruebas no representan el uso real de los lenguajes &lt;span style="font-style: italic;"&gt;in the wild&lt;/span&gt;, y todas las advertencias de costumbre cuando se habla de benchmarks. Pero... mientras no haya una forma científica de comparar los lenguajes, una prueba justa es al menos un indicativo a considerar.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-3121941527502949278?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/3121941527502949278/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=3121941527502949278' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/3121941527502949278'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/3121941527502949278'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/01/alternativa-al-c-ocaml.html' title='Alternativa al C: O&apos;Caml'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-361290909324439230</id><published>2007-01-19T11:32:00.000-08:00</published><updated>2007-01-19T12:33:46.361-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>Que viene despues de "C"?: "D"</title><content type='html'>Habiendo establecido que el lenguaje C es una opción cada vez menos atractiva para la programación de sistemas, cabe preguntar: cual es la alternativa? Existen varias, entre ellas:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;C++&lt;/li&gt;&lt;li&gt;D&lt;/li&gt;&lt;li&gt;OCaml&lt;/li&gt;&lt;li&gt;SML&lt;/li&gt;&lt;/ul&gt;La opción mas obvia, el C++ es la menos interesante. Dado que el  C++ es una extensión del C cuyo objetivo era mantener la compatibilidad con el mismo a nivel de código fuente, presenta las mismas debilidades. C++ es decepcionante en muchos aspectos. No va lo suficientemente lejos en su intención renovadora. Ofrece programación orientada a objetos y templates, pero no hace ningún esfuerzo por eliminar las debilidades del C. No agrega recolección de basura y su sintaxis es perversamente compleja. Pese a todo ello el C++ conquisto parte del mercado del C.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Por que?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;Precisamente debido a su bajo perfil pudo el C++ colarse en el mercado. Casi puedo escuchar el razonamiento de los primeros gerentes en adoptarlo en sus proyectos: "Quieres cambiarlo todo para que nada cambie? Quieres mantenerte a la moda sin arriesgar un ápice? C++ es para ti". &lt;/span&gt;&lt;span style="font-size:100%;"&gt;Sumele a ello la inercia de la interacción con librerías y código heredado, el temor al reentrenamiento, y tendremos un panorama en el que el el heredero de C debía provenir de su mismo linaje.&lt;/span&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-size:100%;"&gt;Desde luego, también estaban los programadores que deseaban probar el paradigma de la programación orientada a objetos y no conocían nada mejor. Como podrían conocer otra cosa? Quien les hablaría de otros paradigmas, como la  programación funcional o implementaciones mas radicales y puras como Smalltalk?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;En donde nos deja todo esto?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Existen otros lenguajes no emparentados directamente con el C que permiten la programación de sistemas y &lt;span style="font-style: italic;"&gt;ofrecen una velocidad igual o superior&lt;/span&gt;. En efecto, el C, el lenguaje mas veloz de la cuadra, el hasta hace poco imbatible líder en rendimiento, se ha visto superado por otros contenedores, los cuales ofrecen además mejoras en otras áreas.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;D&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Sobre las alternativas en el paradigma funcional (OCaml y SML) hablaré en otra ocasión. Centremonos en el mas clásico D. &lt;a href="http://www.digitalmars.com/d"&gt;El lenguaje D&lt;/a&gt; es a la programación de sistemas lo que Java es a la programación de aplicaciones generales: la satisfacción a la promesa incumplida por C++ de un mejor C.&lt;br /&gt;&lt;br /&gt;D no pretende ser compatible a nivel de código fuente con C. Sin embargo, si ofrece compatibilidad a nivel binario. Esta característica clave ya lo separa del montón. Para que un lenguaje de alto rendimiento aspire tener algún éxito, debe necesariamente poder interoperar con las librerías heredadas. Muchos lenguajes conceptualmente mas interesantes que el C han fracasado por el problema del huevo y la gallina (o es el programador y la librería?): El lenguaje es interesante pero no se usa para el desarrollo porque no tiene suficientes librerías, las cuales no son escritas porque no hay suficientes programadores trabajando en el lenguaje porque... no tiene suficientes librerías.&lt;br /&gt;&lt;br /&gt;D ha escapado graciosamente a este circulo vicioso al no reinventar la rueda. Las estructuras de datos entre C y D son compatibles. Además, D usa la misma ABI que C. Esto significa que, dado un binario, no hay forma de distinguir si proviene de código fuente escrito en C o en D.&lt;br /&gt;&lt;br /&gt;Pero D ofrece mucho mas que compatibilidad binaria:&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;Recolección de basura con capacidad de ser desactivada, permitiendo el manejo manual de la memoria.&lt;/li&gt;&lt;li&gt;Programación orientada a objetos.&lt;/li&gt;&lt;li&gt;Eliminación de las arbitrariedades e inconsistencias del C.&lt;/li&gt;&lt;li&gt;...manteniendo una sintaxis semejante.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Eliminación del preprocesador de texto.&lt;/li&gt;&lt;li&gt;Un poderoso sistema de tipos.&lt;/li&gt;&lt;li&gt;Las mas importantes estructuras de datos están predefinidas en el lenguaje.&lt;/li&gt;&lt;li&gt;Implementación en software libre.&lt;/li&gt;&lt;/ul&gt;En definitiva, en la clase de lenguajes imperativos destinados a la programación de sistemas o aplicaciones, ya existe una alternativa viable a C/C++. Solo el miedo irracional a nuevas alternativas mantendrá al C en su posición actual.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-361290909324439230?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/361290909324439230/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=361290909324439230' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/361290909324439230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/361290909324439230'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/01/que-viene-despues-de-c-d.html' title='Que viene despues de &quot;C&quot;?: &quot;D&quot;'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-3695110111834011284</id><published>2007-01-15T09:44:00.000-08:00</published><updated>2007-01-15T09:46:15.247-08:00</updated><title type='text'>Migración a Blogger</title><content type='html'>He migrado todas las entradas del blog a un nuevo proveedor,  &lt;a href="http://www2.blogger.com/"&gt;http://www2.blogger.com/&lt;/a&gt;. Por esta razón todos los post previos a este tienen la misma fecha.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-3695110111834011284?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/3695110111834011284/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=3695110111834011284' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/3695110111834011284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/3695110111834011284'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/01/migracin-blogger.html' title='Migración a Blogger'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-6581659431788673346</id><published>2007-01-15T09:43:00.001-08:00</published><updated>2007-01-15T09:43:52.961-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>El mal C</title><content type='html'>&lt;p&gt;No deja de resultar paradójico que las características que hacen que un lenguaje triunfe suelen ser las mismas que ocasionan que este deje de ser una alternativa viable. Esta aparente paradoja se entiende cuando se analizan los cambios en el entorno: mientras un lenguaje sigue siendo básicamente el mismo conforme pasa el tiempo, el poder de computo, la memoria y el tipo de problemas evolucionan continuamente.&lt;/p&gt; &lt;p&gt;En una entrada anterior comente que hizo grande al C. Ahora comentare  por que el C es cada vez menos una opción valida en un conjunto cada vez mas grande de problemas.&lt;br /&gt;Las principales características que evidencian la edad del C son:&lt;/p&gt; &lt;ul&gt;&lt;li&gt;Sin colección de memoria&lt;/li&gt;&lt;li&gt;Sistema de tipos débil&lt;/li&gt;&lt;li&gt;Muy de bajo nivel&lt;/li&gt;&lt;li&gt;Pobre especificación&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;La falta de un recolector de memoria, la cual es una atractiva característica en la programación de sistemas es una pesadilla en casi cualquier otro ámbito. Con excepciones limitadas a cierto tipo de problemas, el ser humano no es mejor administrando la memoria que el compilador. Esta simple verdad es difícil de aceptar por los miembros de la vieja escuela, incluso cuando ellos mismos confían &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;rutinariamente&lt;/span&gt; en el compilador para optimizar su código.&lt;/p&gt; &lt;p&gt;El sistemas de tipo del C es otra de esas características que son una bendición/maldición. En el momento de su diseño, el sistema de tipos del C era elogiable: lo suficientemente simple para ser implementado sucintamente, lo suficientemente poderoso para generar código optimizado, lo suficientemente flexible para competir con el ensamblador.  Eso fue entonces. Ahora existen sistemas de tipos mas poderosos que permitir expresar los problemas de manera mas clara y ahorrar lineas de código. Estos mismos sistemas, al ser mas estrictos, permiten hacer mas y mejores optimizaciones, por lo cual el C ya no es el lenguaje mas rápido del oeste (&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-corrected" id="SPELLING_ERROR_1"&gt;véase&lt;/span&gt; el lenguaje D, &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Ocaml&lt;/span&gt; o &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;SML&lt;/span&gt;).&lt;/p&gt; &lt;p&gt;Otro aspecto que ha cambiado en el ecosistema, es que con el aumento en la velocidad de los procesadores y su memoria, muchas tareas  privilegian el tiempo de programación sobre el tiempo de ejecución. Esto hace que el C sea un lenguaje de muy bajo nivel. La administración de sistemas, la cual se hacia antes con C, se hace ahora con &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;bash&lt;/span&gt;, &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;perl&lt;/span&gt; o &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;python&lt;/span&gt;. El desarrollo de aplicaciones &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;web&lt;/span&gt; es dominada por lenguajes interpretados. Incluso el uso de lenguajes mas flexibles ha llegado al escritorio de la mano de java/C#-mono/&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;tcl&lt;/span&gt;-&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;tk&lt;/span&gt;/&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;python&lt;/span&gt;.&lt;/p&gt; &lt;p&gt;El ultimo punto, la pobre especificación del C tiene que ver con el hecho que el lenguaje, en aras de permitirle al &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;implementador&lt;/span&gt; obtener la máxima eficiencia en la plataforma de destino, se &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-corrected" id="SPELLING_ERROR_12"&gt;negó&lt;/span&gt; a regular de manera completa el comportamiento del lenguaje. Aunque admito que este seria un problema aun mas grave de no haber sido superado por la incompatibilidad entre librerías en el mundo UNIX… &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-6581659431788673346?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/6581659431788673346/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=6581659431788673346' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/6581659431788673346'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/6581659431788673346'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/01/el-mal-c.html' title='El mal C'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-5467315826790125497</id><published>2007-01-15T09:42:00.000-08:00</published><updated>2007-01-15T09:43:08.376-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>El buen C</title><content type='html'>&lt;p&gt;Con mas de treinta años de existencia, el lenguaje C aun es uno de los mas usados para escribir las aplicaciones con las que el usuario final se relaciona. Virtualmente todos los sistemas operativos de uso masivo son escritos en el, al igual que muchas aplicaciones en las que la velocidad es critica.&lt;/p&gt; &lt;p&gt;Si bien las costuras del lenguaje tienen tiempo siendo evidentes, hoy quiero escribir de las características que hicieron al C atractivo durante este periodo. En otro momento escribiré sobre los elementos que lo hacen hoy día, a mi modo de ver, dispensable.&lt;/p&gt; &lt;p&gt;En la época en la que el C fue desarrollado los recursos del sistema eran sumamente escasos para los estándares actuales. Los costosos minicomputadores median su memoria en Kilobytes en vez de gigabytes y la programación en ensamblador aun era común.&lt;/p&gt; &lt;p&gt;Bajo estas condiciones el C hizo lo mejor que pudo:&lt;/p&gt; &lt;ul&gt;&lt;li&gt;Permitir expresiones aritméticas y lógicas en alto nivel, siguiendo la tradición de los lenguajes imperativos que lo precedieron.&lt;/li&gt;&lt;li&gt;Permitir el manejo de la memoria con una flexibilidad comparable al del lenguaje ensamblador.&lt;/li&gt;&lt;li&gt;Usar un sistema de tipos que permite la generación de código optimizado.&lt;/li&gt;&lt;li&gt;Dejar el manejo de memoria al programador.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Estas características le valieron al C el ser considerado el lenguaje de “alto-bajo nivel”: lo suficientemente alto como para que no fuera tedioso escribir código para el procesamiento de datos y lo suficientemente bajo para sustituir al ensamblador el 99.9% de las veces. Sumesele a ello que fue el lenguaje utilizado para escribir el sistema operativo UNIX y se tiene una combinación ganadora.&lt;/p&gt; &lt;p&gt;La razón por la que el lenguaje C se ha mantenido saludable durante estas décadas (además de la inercia causada por el volumen de librerías a su disposición) es que durante todo este tiempo no ha habido alternativas creíbles e interoperables que permitan hacer programación de sistemas. El controlar ese nicho ha mantenido la preponderancia del C en la escritura de sistemas operativos y librerías de soporte.&lt;/p&gt; &lt;p&gt;Tal situación podría estar por cambiar, aunque eso es motivo para otro post. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-5467315826790125497?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/5467315826790125497/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=5467315826790125497' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/5467315826790125497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/5467315826790125497'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/01/el-buen-c.html' title='El buen C'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-4354577453104606932</id><published>2007-01-15T09:39:00.000-08:00</published><updated>2007-01-15T09:42:13.284-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Sistemas Operativos'/><title type='text'>Hacia el Sistema Operativo del siglo XXI</title><content type='html'>&lt;p&gt;&lt;a href="http://programatica.cs.pdx.edu/House/"&gt;Hay&lt;/a&gt; &lt;a href="http://l4hq.org/projects/os/"&gt;muchos&lt;/a&gt; &lt;a href="http://namesys.com/v4/v4.html#etc_passwd"&gt;conceptos&lt;/a&gt; interesantes en el desarrollo de sistemas operativos. Buena parte de ellos son diseños totalmente nuevos. Si bien el desarrollo desde cero ofrece el terreno óptimo para la innovación, experiencias del pasado sugiere (el computador personal, MSDOS, ethernet…) que la evolución de los sistemas actuales tiene mayores probabilidades de éxito.&lt;/p&gt; &lt;p&gt;En este orden de ideas, cuales son las áreas en las que Linux necesita evolucionar para hacerse mas flexible y coherente? He aquí algunas posibilidades:&lt;/p&gt; &lt;ul&gt;&lt;li&gt;Una nueva jerarquía en el filesystem: La jerarquía de directorios de linux, si bien es mas coherente que la de Windows, aun tiene mucho espacio para mejorar. Otros Unixes ya han comenzado el proceso, desde NeXT, hasta Mac OSX. Un ejemplo interesante dentro del mundo del Linux es &lt;a href="http://www.gobolinux.org/"&gt;Gobolinux&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Paquetes para aplicaciones: Los sistemas de paquetes dependen de la jerarquía actual en el sistema de archivos, lo cual tiene sus inconvenientes: esparcen los archivos de una apelación entre varios directorios y tienen dificultades con múltiples versiones de librerías.&lt;/li&gt;&lt;li&gt;Un nuevo sistema de archivos: En particular uno que permita asociar propiedades a los archivos. La mas reciente versión de ReiserFS &lt;em&gt;podría&lt;/em&gt; permitirlo a través de plugins.&lt;/li&gt;&lt;li&gt;Nuevos mecanismos de seguridad: La seguridad de UNIX basada en usuario-grupo-otros ya esta mostrando su edad. Si bien es suficiente para muchos entornos, en la actualidad ya hay varias opciones con distintos grados de utilidad.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Estos cambios son superficiales y pueden implementarse en nuevas distribuciones sin tocar el núcleo. Hay otras mas ambiciosas, las cuales requieren abandonar Linux tal y como lo conocemos. En futuros artículos comentare algunos de esos cambios.&lt;/p&gt; &lt;p&gt;Uno en particular, es abandonar el mantra de UNIX “todo es un archivo”. Es cierto, esa concepción fue una de sus grandes fortalezas, y tal vez la mas influyente. Sin embargo, la vieja conseja nunca fue del todo cierta. Comenzando con la división entre dispositivos de bloque y de carácter. Adicionalmente, las infames llamadas ioctl también conocidas como todo-lo-que-no-cabe-en-la-interface-de-archivos-va-acá. Un paso adelante seria el reconocimiento que todo no es un archivo y adoptar un enfoque mas liberal. En vez de tener una jerarquía de archivos, el sistema seria un espacio de nombres de &lt;em&gt;objetos&lt;/em&gt;.&lt;/p&gt; &lt;p&gt;Sustituir “archivos” por “objetos” puede sonar cosmético, pero elimina la necesidad de ioctl, homogeniza los conceptos y permite al SO adaptarse a necesidades cambiantes. Desarrollare el concepto en próximo artículos. &lt;/p&gt;                  &lt;!--    &lt;rdf:rdf rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" dc="http://purl.org/dc/elements/1.1/" trackback="http://madskills.com/public/xml/rss/module/trackback/"&gt;   &lt;rdf:description about="http://190.36.169.2/archives/5" identifier="http://190.36.169.2/archives/5" title="Hacia el Sisema Operativo del Siglo XXI" ping="http://190.36.169.2/archives/5/trackback/"&gt; &lt;/rdf:RDF&gt;   --&gt;                              &lt;h2 id="post-4"&gt;&lt;br /&gt;&lt;/h2&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-4354577453104606932?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/4354577453104606932/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=4354577453104606932' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/4354577453104606932'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/4354577453104606932'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/01/hacia-el-sistema-operativo-del-siglo.html' title='Hacia el Sistema Operativo del siglo XXI'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-5333118819636903958</id><published>2007-01-15T09:38:00.000-08:00</published><updated>2007-01-15T09:39:25.190-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Teoría de la Computación'/><category scheme='http://www.blogger.com/atom/ns#' term='Programación'/><title type='text'>Por que calcular es mejor que esquematizar?</title><content type='html'>&lt;p&gt;En http://www.cs.kent.ac.uk/people/staff/dat/miranda/wadler87.pdf se puede encontrar el &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;paper&lt;/span&gt; de &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Philip&lt;/span&gt; &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Wadler&lt;/span&gt; “&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Why&lt;/span&gt; &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;calculating&lt;/span&gt; &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;is&lt;/span&gt; &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;better&lt;/span&gt; &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;than&lt;/span&gt; &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;scheming&lt;/span&gt;”. Este &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;paper&lt;/span&gt; compara lenguajes de la familia &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;lisp&lt;/span&gt;/&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;scheme&lt;/span&gt; con lenguajes tipo miranda/&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;haskell&lt;/span&gt; en el contexto del excelente libro de &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;Abelson&lt;/span&gt; y &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;Sussman&lt;/span&gt; “&lt;a href="http://mitpress.mit.edu/book-home.tcl?isbn=0262011530"&gt;&lt;em&gt;&lt;strong&gt;&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;Structure&lt;/span&gt; &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;and&lt;/span&gt; &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;Interpretation&lt;/span&gt; &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;of&lt;/span&gt; &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;Computer&lt;/span&gt;      &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;Programs&lt;/span&gt;&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;” (&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;SICP&lt;/span&gt;).&lt;/p&gt; &lt;p&gt;El &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;paper&lt;/span&gt; analiza temas aun no resueltos en el área como:&lt;/p&gt; &lt;ul&gt;&lt;li&gt;Definición de tipos&lt;/li&gt;&lt;li&gt;Notación prefija &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;vs&lt;/span&gt;. &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;infija&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Las virtudes del sistema de macros de &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;lisp&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Su conclusión? Que la notación &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;infija&lt;/span&gt;, la posibilidad de declarar tipos de datos, el uso de tipos de datos algebraicos y el emparejamiento de patrones hacen que la intención del programador sea expresada de manera mas clara y concisa; que la identidad entre código y datos en &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;lisp&lt;/span&gt; puede ser un importante factor de confusión para los programadores noveles (y los no tanto); que la evaluación perezosa ofrece una elegante &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;homogenización&lt;/span&gt; de los lenguajes que la poseen.&lt;/p&gt; &lt;p&gt;En definitiva, &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;lisp&lt;/span&gt; no sale muy bien parado en el &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-corrected" id="SPELLING_ERROR_30"&gt;análisis&lt;/span&gt; de &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_31"&gt;Wadler&lt;/span&gt;. Tal vez ello le condujo al desarrollo de &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_32"&gt;Haskell&lt;/span&gt;… &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-5333118819636903958?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/5333118819636903958/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=5333118819636903958' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/5333118819636903958'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/5333118819636903958'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/01/por-que-calcular-es-mejor-que.html' title='Por que calcular es mejor que esquematizar?'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7127368407826099674.post-7890998362810959622</id><published>2007-01-15T09:37:00.000-08:00</published><updated>2007-01-15T09:38:12.226-08:00</updated><title type='text'>Sobre Strong Typed</title><content type='html'>Strong Typed es un blog dedicado al estudio de la ciencia de la computación, programación y sistemas operativos. Otros temas afines, en lo tocante a matemática también tienen cabida acá.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7127368407826099674-7890998362810959622?l=strongtyped.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://strongtyped.blogspot.com/feeds/7890998362810959622/comments/default' title='Comentarios de la entrada'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7127368407826099674&amp;postID=7890998362810959622' title='0 Comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/7890998362810959622'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7127368407826099674/posts/default/7890998362810959622'/><link rel='alternate' type='text/html' href='http://strongtyped.blogspot.com/2007/01/sobre-strong-typed.html' title='Sobre Strong Typed'/><author><name>José Dinuncio</name><uri>http://www.blogger.com/profile/15730779978022115418</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='18' height='32' src='http://bp1.blogger.com/_0fcYXkGlbzs/R92Uoxgf_TI/AAAAAAAAAAM/kZcuyd6DsMU/S220/meBlade-final.jpg'/></author><thr:total>0</thr:total></entry></feed>
