<?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-1486787303054252615</id><updated>2012-01-19T15:51:51.745+01:00</updated><category term='narrativa'/><category term='ensamblador'/><category term='patrones de diseño'/><category term='rangos'/><category term='manejo de memoria'/><category term='introducción a la programación'/><category term='ingeniería del software'/><category term='iteradores'/><category term='macros'/><category term='variancia'/><category term='teoria de tipos'/><category term='matemáticas'/><category term='lenguaje natural'/><category term='interfaces'/><category term='grafos'/><category term='programación genérica'/><category term='video y gráficos'/><category term='lenguajes de programación'/><category term='teoría de la información'/><category term='metablog'/><category term='señales'/><category term='calculabilidad'/><category term='circuitos'/><category term='varios'/><category term='miniSL'/><category term='semántica formal'/><category term='Máquinas virtuales'/><category term='internet'/><category term='japonés'/><category term='algoritmos'/><category term='diseño'/><category term='audio y música'/><category term='c++'/><category term='LISP'/><title type='text'>El manantial de bits</title><subtitle type='html'>Información aleatoria proveniente de un ser racional</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default?start-index=101&amp;max-results=100'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>179</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-7192608959583384916</id><published>2012-01-19T15:51:00.000+01:00</published><updated>2012-01-19T15:51:51.750+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='varios'/><title type='text'>Pasos en la profesión</title><content type='html'>Una idea que quiero concretar antes de que se me olvide.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;div&gt;&lt;strong&gt;Sueños&lt;/strong&gt;: En este momento sólo se tienen ideas de la profesión. Suele ocurrir cuando se es aún un niño.&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div&gt;&lt;strong&gt;Realización&lt;/strong&gt;: Las ideas se concretan en obras. Si se quería ser alfarero, se realizan las primeras vasijas. Si se quería ser programador, se terminan los primeros programas.&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Estudio&lt;/strong&gt;: Siempre me ha llamado la atención que, sea cual sea la disciplina que se estudie, siempre hay una grandísima cantidad de temas de estudio. Ni que decir tiene que para progresar en la profesión, hay que estudiar. Aunque tampoco demasiado porque si no, no pasamos al siguiente punto.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Práctica&lt;/strong&gt;: Generalmente el resultado de la realización de ideas no es lo que se tenía en mente. Hay que practicar para que el abismo entre imaginación y realidad se haga más somero. Este es el paso más difícil desde mi punto de vista, ya que se debe trabajar mucho pero no hay realimentación de resultados.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Mercado&lt;/strong&gt;: Llega un momento en el que las obras realizadas se pueden mostrar al público e, incluso, algunas, vender. Estamos tocando el mercado. Empieza a haber resultados.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Profesión&lt;/strong&gt;: Es cuando se pueden obtener ingresos regulares de lo que se crea y esos ingresos son suficientes para vivir.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Reconocimiento&lt;/strong&gt;: El trabajo que se realiza es reconocido entre los que se dedican a lo mismo.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Éxito&lt;/strong&gt;: Simplemente, los ingresos son muy superiores a lo que se necesita para vivir. Si se dejase de trabajar, seguiríamos teniendo ingresos por regalías o licencias.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Fama&lt;/strong&gt;: El trabajo que se realiza es reconocido entre los que no se dedican a lo mismo.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Inmortalidad&lt;/strong&gt;: El trabajo que se realiza sigue siendo reconocido generaciones después.&lt;/li&gt;&lt;/ol&gt;Es interesante dar un factor de filtrado a cada paso. Así, si de cada 10 que tienen ideas, 1 las realiza; el factor es de 10. De realización a práctica el factor puede ser de 5, pero de práctica a mercado creo que es 20 o más. De mercado a profesión puede ser de 5 o así. Es decir que, a bote pronto, una de cada 5000 personas puede vivir de sus sueños.&lt;br /&gt;&lt;br /&gt;Es una estimación algo burda, pero tomándolo como un &lt;a href="http://en.wikipedia.org/wiki/Fermi_problem"&gt;problema de Fermi&lt;/a&gt; el resultado nos puede dar a ver la dificultad de la tarea.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-7192608959583384916?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/7192608959583384916/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2012/01/pasos-en-la-profesion.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/7192608959583384916'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/7192608959583384916'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2012/01/pasos-en-la-profesion.html' title='Pasos en la profesión'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-7061664420929701840</id><published>2011-12-01T12:43:00.001+01:00</published><updated>2011-12-02T09:11:18.350+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='miniSL'/><title type='text'>miniSL parte 17 - El analizador léxico</title><content type='html'>Hasta &lt;a href="http://elmanantialdebits.blogspot.com/2011/09/minisl-parte-15-funciones-auxiliares-de.html"&gt;aquí&lt;/a&gt; hemos visto la semántica de nuestro lenguaje script mínimo. A partir de ahora, empezamos con el reconocedor sintáctico. Debido a que nuestro lenguaje tiene una sintaxis no trivial, nos ocupará bastante tiempo describirlo. (Una &lt;a href="http://en.wikipedia.org/wiki/S-expression"&gt;sintaxis trivial &lt;/a&gt;es la del LISP)&lt;br /&gt;&lt;br /&gt;Generalmente los &lt;b&gt;reconocedores sintácticos&lt;/b&gt; se separan en dos partes (por ejemplo, el clásico &lt;a href="http://dinosaur.compilertools.net/"&gt;LEX&amp;amp;YACC&lt;/a&gt;). La primera llamada analizador léxico (&lt;a href="http://en.wikipedia.org/wiki/Lexical_analysis"&gt;scanner o lexer&lt;/a&gt;) reconoce varios caracteres del fichero de entrada (por ejemplo &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;3&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;, &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;5&lt;/span&gt; y &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;6&lt;/span&gt;) y nos devuelve un elemento significativo llamado &lt;a href="http://en.wikipedia.org/wiki/Token_(parser)#Token"&gt;token&lt;/a&gt; (el número 356). La segunda parte es el analizador sintáctico propiamente dicho (llamado &lt;a href="http://en.wikipedia.org/wiki/Parser"&gt;parser&lt;/a&gt;) que acepta los tokens y devuelve un &lt;a href="http://en.wikipedia.org/wiki/Abstract_syntax_tree"&gt;AST&lt;/a&gt;. Veremos esta segunda parte más adelante y nos centramos en la generación de tokens.&lt;br /&gt;&lt;br /&gt;En miniSL hay varios &lt;b&gt;tipos de token&lt;/b&gt; que se listan en la enumeración TOKEN_TYPE.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;enum TOKEN_TYPE { T_NONE, T_RAW, T_LITERAL, T_SYMBOL, T_NAME };&lt;br /&gt;&lt;/pre&gt;El tipo T_NONE indica &lt;b&gt;que no se han reconocido &lt;/b&gt;los caracteres. Usamos T_RAW cuando el token es un &lt;b&gt;único carácter&lt;/b&gt; (por ejemplo, una llave &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;{&lt;/span&gt; o una coma &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;, &lt;/span&gt;). Es importante saber aquí que el final de fichero, un carácter llamado &lt;a href="http://en.wikipedia.org/wiki/End-of-file"&gt;EOF&lt;/a&gt;, también se guarda en un token de tipo T_RAW. El tipo de token T_LITERAL indica o bien un número, o bien una cadena, en general una celda &lt;b&gt;literal&lt;/b&gt;. Guardaremos el valor que corresponda en una celda del tipo adecuado. El token de tipo T_SYMBOL es un &lt;b&gt;identificador formado por símbolos&lt;/b&gt; tales como &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;+&lt;/span&gt;, &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;lt;=&lt;/span&gt; o &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;!=&lt;/span&gt;. Finalmente, T_NAME se usa para &lt;b&gt;identificadores alfanuméricos&lt;/b&gt; como &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;x&lt;/span&gt;, &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;map&lt;/span&gt; o &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;iterator&lt;/span&gt;. Tanto los tokens de tipo T_SYMBOL como los T_NAME guardan el identificador en una celda de tipo STRING_LIT.&lt;br /&gt;&lt;br /&gt;La información del tipo de token y la información relativa al token se guardan en la estructura TOKEN que es la siguiente.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;struct TOKEN&lt;br /&gt; {&lt;br /&gt;  TOKEN() : type(T_NONE) {}&lt;br /&gt;  TOKEN(TOKEN_TYPE t, CELL* d) : type(t), data(d) {}&lt;br /&gt;  TOKEN(ISTREAM::int_type r) : type(T_RAW), raw(r) {}&lt;br /&gt;&lt;br /&gt;  TOKEN_TYPE type;&lt;br /&gt;  union&lt;br /&gt;  {&lt;br /&gt;   CELL* data;&lt;br /&gt;   ISTREAM::int_type raw;&lt;br /&gt;  };&lt;br /&gt; };&lt;br /&gt;&lt;/pre&gt;Los constructores fuerzan que cuando el TOKEN sea de tipo T_RAW, la información relacionada es un único carácter guardado en la variable miembro raw. En los otros tipos lo guardaremos en la celda apuntada por la variable miembro data. Esta estructura &lt;a href="http://c2.com/cgi/wiki?TypeSafe"&gt;no es muy segura&lt;/a&gt; porque podríamos colar un T_RAW en el constructor que toma una celda. Vigilaremos que eso no ocurra.&lt;br /&gt;&lt;br /&gt;Ahora queda &lt;b&gt;leer&lt;/b&gt; los caracteres y &lt;b&gt;generar&lt;/b&gt; el token correspondiente. De eso se encarga la función ReadToken(). La función ReadToken() devuelve el siguiente token leído y lo consume. De esta forma, cada vez que llamemos a ReadToken() &lt;b&gt;avanzaremos&lt;/b&gt; por el fichero hasta obtener el carácter de &lt;b&gt;fin de fichero&lt;/b&gt; EOF. Sin embargo, muchas veces &lt;b&gt;no querremos avanzar&lt;/b&gt; por el fichero. Querremos únicamente saber cuál es el siguiente token, &lt;b&gt;sin consumirlo&lt;/b&gt;. De esto se encarga la función PeekToken().&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="color: #666666;"&gt;Nota: “Peek” en inglés significa “ojear” en el sentido de mirar a hurtadillas.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;Script::TOKEN Script::PeekToken(ISTREAM&amp;amp; i)&lt;br /&gt;{&lt;br /&gt; if(m_Ahead.type!=T_NONE)&lt;br /&gt;  return m_Ahead;&lt;br /&gt;&lt;br /&gt; m_Ahead=ReadToken(i);&lt;br /&gt; return m_Ahead;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;El funcionamiento de PeekToken() es muy simple porque se basa en ReadToken(). Primero, comprueba si ya hemos leído el siguiente token que se ha guardado en m_Ahead. Esta no es más que una variable miembro en la clase Script (para los que no recuerden la clase Script, &lt;a href="http://elmanantialdebits.blogspot.com/2010/12/minisl-parte-7-las-cadenas-internas.html"&gt;ver la parte séptima&lt;/a&gt;).&lt;br /&gt;&lt;pre class="brush:cpp"&gt;TOKEN m_Ahead;&lt;br /&gt;&lt;/pre&gt;Si m_Ahead guarda ya el token leído, lo devuelve. Si m_Ahead no contiene el token leído, lo lee con ReadToken() y lo guarda en m_Ahead para siguientes PeekToken()s. De esta manera, llamar a PeekToken() varias veces, sólo llama a ReadToken() la primera vez y usa m_Ahead el resto.&lt;br /&gt;&lt;br /&gt;¿Por qué es importante saber cómo funciona PeekToken() antes de saber cómo funciona ReadToken()? Muy sencillo. Si m_Ahead contiene un token y llamamos a ReadToken(), hay que vaciar m_Ahead. De esta forma se consume. &lt;br /&gt;&lt;pre class="brush:cpp"&gt;Script::TOKEN Script::ReadToken(ISTREAM&amp;amp; i)&lt;br /&gt;{&lt;br /&gt; if(m_Ahead.type!=T_NONE)&lt;br /&gt; {&lt;br /&gt;  TOKEN t=m_Ahead;&lt;br /&gt;  m_Ahead.type=T_NONE;&lt;br /&gt;  return t;&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;A partir de este momento empieza, realmente la &lt;b&gt;lectura de caracteres&lt;/b&gt; dentro de ReadToken(). La primera acción es saltarse el espacio en blanco. Nuestra sintaxis &lt;a href="http://en.wikipedia.org/wiki/Free-form_language"&gt;va a ignorar los espacios en blanco&lt;/a&gt;.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;SkipWhitespace(i);&lt;br /&gt;&lt;/pre&gt;Luego, vamos a ojear el siguiente carácter. Podréis comprobar que no he inventado nada nuevo al llamar PeekToken() a mi función ya que la biblioteca estándar de C++ llama a esta función peek().&lt;br /&gt;&lt;pre class="brush:cpp"&gt;ISTREAM::int_type c=i.peek();&lt;br /&gt;&lt;/pre&gt;Según sea ese carácter, decidiremos leer un token de un tipo  o de otro. Si es una doble comilla, será una cadena.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;if(c=='"')     return TOKEN(T_LITERAL, &amp;amp;ReadString(i, false));&lt;br /&gt;&lt;/pre&gt;Si es un símbolo &lt;a href="http://en.wikipedia.org/wiki/Extended_ascii"&gt;ASCII extendido&lt;/a&gt;, lo examinaremos. Para eso usamos la comparación &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;c&amp;lt;256&lt;/span&gt;.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;if(c&amp;lt;256)&lt;br /&gt; {&lt;br /&gt;  if(isalpha(c) || c=='_') return ReadName(i);&lt;br /&gt;  if(isdigit(c))    return TOKEN(T_LITERAL, &amp;amp;ReadNumber(i));&lt;br /&gt;  if(CELL::IsSymbol(c))  return TOKEN(T_SYMBOL, &amp;amp;ReadSymbol(i));&lt;br /&gt;&lt;/pre&gt;Hasta aquí todo sencillo. Si es un carácter alfanumérico, lo leemos como un nombre. Si es un dígito, como un número. Si es un símbolo, como símbolo.&lt;br /&gt;&lt;br /&gt;Pero ahora vamos a añadir una &lt;b&gt;puerta trasera&lt;/b&gt; que ya ha sido muy útil. De hecho, nos ha permitido &lt;a href="http://elmanantialdebits.blogspot.com/2011/02/minisl-parte-9-imprimiendo-celdas.html"&gt;imprimir de manera uniforme los identificadores&lt;/a&gt;. Básicamente consiste en poner una &lt;b&gt;arroba delante de una cadena&lt;/b&gt;. Entonces, en vez de cadena tomamos ese token como un &lt;b&gt;identificador&lt;/b&gt;. Será lo mismo escribir &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;mi_variable&lt;/span&gt; que &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;@”mi_variable”&lt;/span&gt;.  También añadiremos la sintaxis de arroba seguido de símbolo con la misma idea. Será lo mismo escribir &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;3+5&lt;/span&gt; que &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;@+(3,5)&lt;/span&gt;.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;if(c=='@') //Symbol or string as name&lt;br /&gt;  {&lt;br /&gt;   i.get();&lt;br /&gt;   if(i.peek()=='"')    return TOKEN(T_NAME, &amp;amp;ReadString(i, true));&lt;br /&gt;   if(CELL::IsSymbol(i.peek())) return TOKEN(T_NAME, &amp;amp;ReadSymbol(i));&lt;br /&gt;   throw L"Expecting a symbol or a string after @";&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;Si el carácter no es ASCII extendido, será probablemente el carácter EOF así que lo guardamos como un token T_RAW. Además, si ninguna de las condiciones anteriores se dio, será un carácter ASCII extendido no usado por otro tipo de token. Deberá ser T_RAW también.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;//Raw one-character token&lt;br /&gt; return TOKEN(i.get());&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="color: #666666;"&gt;Nota: Esto no funciona con UTF-8 que sería lo suyo. Introduciríamos una complejidad que sobrepasa los objetivos de este pequeño lenguaje de script.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Y ya hemos leído el token. Ahora queda examinar todas esas funciones de ayuda que hemos utilizado. Empezaremos con SkipWhitespace() en la siguiente parte y seguiremos con ReadString() y demás más adelante.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-7061664420929701840?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/7061664420929701840/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/12/minisl-parte-17-el-analizador-lexico.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/7061664420929701840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/7061664420929701840'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/12/minisl-parte-17-el-analizador-lexico.html' title='miniSL parte 17 - El analizador léxico'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-1553376933895308704</id><published>2011-11-16T12:57:00.000+01:00</published><updated>2011-11-16T12:57:23.173+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='introducción a la programación'/><title type='text'>Historia de la gestión de símbolos</title><content type='html'>&lt;span style="color: red;"&gt;&lt;b&gt;PARTE I: COMPILADOR Y VINCULADOR&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hoy en día damos por hecho muchas cosas que han costado muchos años descubrir, usar y pulir. Una de ellas es la gestión de los símbolos. Allá por los años cincuenta, si alguien quería hacer un programa debía escribir el &lt;b&gt;código fuente&lt;/b&gt; y, como en estos años los compiladores eran muy simples, directamente te generaban el &lt;b&gt;código ejecutable&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-pnlDswaDveg/TsOQWFFwajI/AAAAAAAAALU/dpChHknfOKw/s1600/Los50.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="106" src="http://2.bp.blogspot.com/-pnlDswaDveg/TsOQWFFwajI/AAAAAAAAALU/dpChHknfOKw/s400/Los50.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Usualmente el código fuente estaba en &lt;a href="http://eltamiz.com/elcedazo/2009/02/10/historia-de-un-viejo-informatico-el-equipamiento-informatico-en-la-decada-de-los-setenta/"&gt;tarjetas perforadas&lt;/a&gt; y el ejecutable se quedaba en memoria, donde se ejecutaba.&lt;br /&gt;&lt;br /&gt;Luego, conforme pasaban los años, los programas se iban haciendo más y más grandes. Recompilar todo cada vez era tedioso y para reutilizar un trozo de código &lt;a href="http://es.wikipedia.org/wiki/No_te_repitas"&gt;hay que volverlo a escribir&lt;/a&gt;. La solución es partir los programas. El problema es que este compilador tan simple no me permite partir los programas.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-Zy5CNXG4YoM/TsORMdbCnzI/AAAAAAAAALc/1IxyQhae9NA/s1600/Los50porPartes.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="140" src="http://2.bp.blogspot.com/-Zy5CNXG4YoM/TsORMdbCnzI/AAAAAAAAALc/1IxyQhae9NA/s400/Los50porPartes.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;La solución fue usar dos pasos a la hora de compilar. El primer paso es la compilación a un código intermedio que se denomina &lt;b&gt;código objeto&lt;/b&gt;. El código objeto es como el código ejecutable, pero tiene marcas de dónde está cada objeto del código (lo que técnicamente se denomina un &lt;b&gt;símbolo exportado&lt;/b&gt;). De ahí el nombre "código objeto". Luego, un segundo paso es el &lt;b&gt;vinculador&lt;/b&gt; (o &lt;b&gt;enlazador&lt;/b&gt;) que lee esas marcas del código objeto y como si fuera un puzle va componiendo el programa ejecutable final y completo.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-VECHqWk3QA0/TsOSFPsVgDI/AAAAAAAAALk/iSvPvwFzmhY/s1600/Los50enlazado.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="218" src="http://1.bp.blogspot.com/-VECHqWk3QA0/TsOSFPsVgDI/AAAAAAAAALk/iSvPvwFzmhY/s400/Los50enlazado.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Esto causa un problema porque... ¿cómo sabe el código fuente de la parte 1 lo que hay en el código fuente de la parte 2 si puede que incluso hayan sido programados por gente completamente distinta?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;PARTE II: SÍMBOLOS Y SÍMBOLOS EXTERNOS&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;A finales de los sesenta apareción un lenguaje que aún hoy es de los más usados. &lt;a href="http://elmanantialdebits.blogspot.com/2011/10/muere-un-grande-de-la-informatica.html"&gt;El lenguaje C&lt;/a&gt;. Una de las virtudes del C es que soluciona el problema antes mencionado. La solución que se usa en C es permitir usar objetos sin definirlos. Esto se realiza mediante lo que se denomina la &lt;b&gt;declaración&lt;/b&gt; del símbolo. La declaración da toda la información necesaria para usar el símbolo, pero no dice qué es. No lo define.&lt;br /&gt;&lt;br /&gt;Lo más usual es declararlos y definirlos que es lo que pongo aquí como ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: cpp"&gt;int a=0;&lt;br /&gt;&lt;br /&gt;double hipotenusa(double x, double y)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;return sqrt(x*x+y*y);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;El código objeto generado por este código fuente de ejemplo tiene lo que técnicamente se denomina dos símbolos: El símbolo "a" y el símbolo "hipotenusa". Ambos están definidos, es decir, que hay un trozo de ese código objeto que se asigna al símbolo "a" y otro trozo de ese código objeto que se asigna al símbolo "hipotenusa". El trozo del símbolo "a" está a cero. El trozo del símbolo "hipotenusa" tiene el código ejecutable de la función hipotenusa.&lt;br /&gt;&lt;br /&gt;El contenido del código objeto sería algo como&lt;br /&gt;&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Símbolo&lt;/th&gt;&lt;th&gt;Objeto asignado&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;a&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;hipotenusa&lt;/td&gt;&lt;td&gt;&lt;pre&gt;{return sqrt(x*x+y*y);}&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Para declarar sin definir los símbolos en C se usa lo siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;extern int a;&lt;br /&gt;&lt;br /&gt;double hipotenusa(double x, double y);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;El código objeto generado por este código fuente de ejemplo tiene dos símbolos: "a" e "hipotenusa". Ninguno está definido, es decir, que este código objeto sólo tiene una lista de los símbolos sin asignarle ningún objeto. Los símbolos sin objeto asignado tienen que obtenerse del exterior cuando el vinculador recomponga el puzle. Son los llamados &lt;b&gt;símbolos externos&lt;/b&gt;, porque se definen en algún otro lugar externo al código fuente donde los declaramos.&lt;br /&gt;&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Símbolo&lt;/th&gt;&lt;th&gt;Objeto asignado&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;a&lt;/td&gt;&lt;td&gt;externo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;hipotenusa&lt;/td&gt;&lt;td&gt;externo&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;PARTE III: USANDO SÍMBOLOS EXTERNOS&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ahora ya sabemos cómo declarar y definir una función en código fuente y cómo usarla desde otro código fuente. Bastará declararla sin definirla.&lt;br /&gt;&lt;br /&gt;programa_parte1.c&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;/* Declaramos y definimos */&lt;br /&gt;void mifuncion(void)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;puts("Esta función está programa_parte1.c");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;programa_parte2.c&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;/* Declaramos pero no definimos (prototipo) */&lt;br /&gt;void mifuncion(void);&lt;br /&gt;&lt;br /&gt;void main(void)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;puts("Esta función está en programa_parte2.c");&lt;br /&gt;&amp;nbsp; &amp;nbsp;mifuncion(); /* Se usa mifuncion() con haberla sólo declarado */&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Primero compilamos&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-362Hhql2TK4/TsOUicx4LxI/AAAAAAAAALs/MTm69lboOYY/s1600/Los70compilado.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="118" src="http://4.bp.blogspot.com/-362Hhql2TK4/TsOUicx4LxI/AAAAAAAAALs/MTm69lboOYY/s400/Los70compilado.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Según el compilador la extensión del código objeto será .o &amp;nbsp; .obj &amp;nbsp; .coff, etc. Los códigos objetos generados serán algo así como muestran las siguientes tablas.&lt;br /&gt;&lt;br /&gt;programa_parte1.obj&lt;br /&gt;&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Símbolo&lt;/th&gt;&lt;th&gt;Objeto asignado&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;mifuncion&lt;/td&gt;&lt;td&gt;&lt;pre&gt;{puts("Esta función está programa_parte1.c");}&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;programa_parte2.obj&lt;br /&gt;&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Símbolo&lt;/th&gt;&lt;th&gt;Objeto asignado&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;mifuncion&lt;/td&gt;&lt;td&gt;externo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;main&lt;/td&gt;&lt;td&gt;&lt;pre&gt;{ puts("Esta función está en programa_parte2.c"); mifuncion(); }&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Ahora pasamos el vinculador o enlazador.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-7eieTz-KM1c/TsOYrKxZzxI/AAAAAAAAAME/JJw6hRVwfH8/s1600/Los70enlazando.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="86" src="http://3.bp.blogspot.com/-7eieTz-KM1c/TsOYrKxZzxI/AAAAAAAAAME/JJw6hRVwfH8/s400/Los70enlazando.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;El vinculador es lo suficientemente inteligente como para ver que el símbolo "mifuncion" está definido en la parte 1 y es un símbolo externo en la parte 2 donde se usa. Entonces, compone ambas partes haciendo que cuando la función main() llame a mifuncion() lo haga correctamente. Finalmente el símbolo "main" es especial y lo usa como &lt;a href="http://en.wikipedia.org/wiki/Entry_point"&gt;punto de entrada&lt;/a&gt; del ejecutable.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;PARTE IV: LOS FICHEROS DE INCLUSIÓN&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ahora sólo queda un detalle menor. ¿Vamos a tener que repetir&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;void mifuncion(void);&lt;/pre&gt;&lt;br /&gt;cada vez que queramos usar la función mifuncion()? ¿Qué pasará si lo que tengo en el código objeto no es una función sino una &lt;a href="http://es.wikipedia.org/wiki/Biblioteca_(inform%C3%A1tica)"&gt;biblioteca&lt;/a&gt; de cincuenta, cien o mil funciones? ¿Voy a tener que escribir todas las que quiera usar una y otra vez en cada fichero fuente que escriba?&lt;br /&gt;&lt;br /&gt;La solución es poner todas las declaraciones en un fichero de cabecera (.h del inglés header). E incluir el fichero con tooodas las definiciones. Esto nos ahorra el escribir cada vez todas las definiciones.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-VHKfWxWeZ4A/TsOYJCDJR2I/AAAAAAAAAL8/NdlooYgBMJg/s1600/Los70inclusion.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="118" src="http://3.bp.blogspot.com/-VHKfWxWeZ4A/TsOYJCDJR2I/AAAAAAAAAL8/NdlooYgBMJg/s400/Los70inclusion.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Este uso de los ficheros de inclusión es común en lenguajes como el C y el C++.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;PARTE V: LOS MÓDULOS&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Realmente, usar un fichero de inclusión es una tontería: ¡ya tenemos los símbolos en el código objeto! ¿No podríamos decir en el código fuente "toma los símbolos de este código objeto"? La respuesta es sí. Existen muchos lenguajes que lo hacen. Entre ellos Java y ActionScript3. A esta acción de extraer símbolos de un código objeto y usarlos en otro código fuente se denomina "&lt;b&gt;importar símbolos&lt;/b&gt;". Al código objeto que exporta los &lt;a href="http://en.wikipedia.org/wiki/Module_(programming)"&gt;símbolos de esta manera&lt;/a&gt; se le denomina &lt;b&gt;módulo&lt;/b&gt; o &lt;b&gt;paquete&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-LZkpetaovB4/TsOaGaLPaII/AAAAAAAAAMM/RwZkv7FleFQ/s1600/Los70importa.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="107" src="http://1.bp.blogspot.com/-LZkpetaovB4/TsOaGaLPaII/AAAAAAAAAMM/RwZkv7FleFQ/s400/Los70importa.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Existen un par de salvedades a este sistema. En primer lugar, el orden de compilación es importante. Debemos compilar los códigos fuentes de manera que cuando usemos un símbolo, el código objeto que lo contiene haya sido generado previamente. Esto significa que no podemos tener ciclos en el uso de referencia aunque &lt;a href="http://msdn.microsoft.com/en-us/library/ms379563(v=vs.80).aspx"&gt;algunos sistemas&lt;/a&gt; mezclan el compilador y el vinculador en un único paso para permitir estos ciclos. En segundo lugar, es importante cómo llamamos a los ficheros de código objeto y dónde los ubicamos en el sistema de fichero.&lt;br /&gt;&lt;br /&gt;Esto último hace que sea necesaria una &lt;a href="http://www.roseindia.net/java/master-java/PackageCategories.shtml"&gt;jerarquía&lt;/a&gt; en los nombres de los módulos, usualmente separados por puntos. Así, un símbolo del sistema de módulos de Java se escribe así "java.lang.NullPointerException" y significa algo como en el directorio "java", en el subdirectorio "lang", el fichero "NullPointerException". Este tipo de nombre de símbolos &lt;a href="http://en.wikipedia.org/wiki/Qualified_name"&gt;compuestos de varias partes&lt;/a&gt; se llaman &lt;b&gt;nombres completamente cualificados&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Es usual en estos sistemas de módulos que cada fichero sólo pueda definir un símbolo. &lt;a href="http://stackoverflow.com/questions/2134784/why-filename-in-java-should-be-same-as-class-name"&gt;Aquél que coincide con el nombre del fichero.&lt;/a&gt; Hay aquí una rigidez. ¿Podríamos separar los nombres de los ficheros de los nombres de los símbolos?&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;PARTE VI: LOS ESPACIOS DE NOMBRE&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Cuando usamos un nombre cualificado como&amp;nbsp; "java.lang.NullPointerException" hemos pensado que "java" es un directorio, pero desde el punto de vista del programador no es más que un nombre que contiene otros nombres, entre ellos "lang". Asimismo "lang" contiene "NullPointerException". Por esta razón, es común llamar a "java" y a "java.lang" un &lt;b&gt;espacio de nombres&lt;/b&gt; (&lt;a href="http://en.wikipedia.org/wiki/Namespace"&gt;namespace&lt;/a&gt; en inglés). En el caso de Java (y de AS3) los espacios de nombres están relacionados con los directorios.&lt;span style="color: red;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Sin embargo, en C# y C++ no es así y pueden definirse espacios de nombres en el código fuente. Eso significa que los códigos objetos exportan los símbolos con sus nombres cualificados y el vinculador tiene que ser un poco más inteligente.&lt;br /&gt;&lt;br /&gt;Modifiquemos el programa anterior para incluir un espacio de nombre llamado "miespacio" usando C++ y añadiré otra "mifuncion" en "otroespacio". El C++ es &lt;a href="http://en.wikipedia.org/wiki/Scope_resolution_operator"&gt;exótico&lt;/a&gt; porque usa :: para separar los nombres cualificados en vez del punto.&lt;br /&gt;&lt;br /&gt;programa_parte1.cpp&lt;br /&gt;&lt;pre class="brush:cpp"&gt;/* Declaramos y definimos */&lt;br /&gt;namespace miespacio&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; void mifuncion(void)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;puts("Esta función está programa_parte1.c y en miespacio");&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;namespace otroespacio&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; void mifuncion(void)&lt;br /&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;puts("Esta función está programa_parte1.c pero en otroespacio");&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;programa_parte2.c&lt;br /&gt;&lt;pre class="brush:cpp"&gt;/* Declaramos pero no definimos (prototipo) dentro de miespacio*/&lt;br /&gt;namespace miespacio { void mifuncion(void); }&lt;br /&gt;&lt;br /&gt;void main(void)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;puts("Esta función está en programa_parte2.c");&lt;br /&gt;&amp;nbsp; &amp;nbsp;miespacio::mifuncion(); /* Se usa miespacio::mifuncion() pero no otroespacio::mifuncion() */&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Si ahora miramos los códigos objeto encontramos los siguientes símbolos.&lt;br /&gt;&lt;br /&gt;programa_parte1.obj&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Símbolo&lt;/th&gt;&lt;th&gt;Objeto asignado&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;miespacio::mifuncion&lt;/td&gt;&lt;td&gt;&lt;pre&gt;{puts("Esta función está programa_parte1.c y en miespacio");}&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&amp;nbsp;&lt;tr&gt;&lt;td&gt;otroespacio::mifuncion&lt;/td&gt;&lt;td&gt;&lt;pre&gt;{puts("Esta función está programa_parte1.c pero en otroespacio");}&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&amp;nbsp;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;programa_parte2.obj&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Símbolo&lt;/th&gt;&lt;th&gt;Objeto asignado&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;miespacio::mifuncion&lt;/td&gt;&lt;td&gt;externo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;main&lt;/td&gt;&lt;td&gt;&lt;pre&gt;{ puts("Esta función está en programa_parte2.c"); miespacio::mifuncion(); }&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-ecHW2t6xgFM/TsOeQFxXrUI/AAAAAAAAAMU/bJvdxd7yZ_4/s1600/Los90espacios.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="228" src="http://2.bp.blogspot.com/-ecHW2t6xgFM/TsOeQFxXrUI/AAAAAAAAAMU/bJvdxd7yZ_4/s400/Los90espacios.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;De esta manera no hay relación entre la ubicación del módulo en el sistema de ficheros y los espacios de nombre que contiene. Esto es importante porque ahora podemos mover el módulo de lugar dentro del disco y no hay que modificar el código fuente.&amp;nbsp;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-1553376933895308704?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/1553376933895308704/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/11/historia-de-la-gestion-de-simbolos.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/1553376933895308704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/1553376933895308704'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/11/historia-de-la-gestion-de-simbolos.html' title='Historia de la gestión de símbolos'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-pnlDswaDveg/TsOQWFFwajI/AAAAAAAAALU/dpChHknfOKw/s72-c/Los50.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-1795239566474208859</id><published>2011-11-10T16:23:00.000+01:00</published><updated>2011-11-10T16:23:10.603+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='LISP'/><category scheme='http://www.blogger.com/atom/ns#' term='semántica formal'/><title type='text'>Semántica natural de LISP - parte 2 - LISP imperativo</title><content type='html'>En la &lt;a href="http://elmanantialdebits.blogspot.com/2011/10/semantica-natural-de-lisp-parte-1-lisp.html"&gt;primera parte&lt;/a&gt; de esta serie homenaje a &lt;a href="http://elmanantialdebits.blogspot.com/2011/10/muere-john-mccarthy.html"&gt;John McCarthy&lt;/a&gt; vimos una semántica de LISP sin permitir la modificación ni de los valores ni de las vinculaciones. Era un LISP funcional. En esta parte vamos a introducir esa posibilidad. Es por tanto un LISP &lt;a href="http://elmanantialdebits.blogspot.com/2010/01/lenguajes-declarativos-y-lenguajes.html"&gt;imperativo&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;La memoria y los contextos&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;En el momento que introducimos cambios, hemos de manejar estados. El estado con el que trabajaremos será la memoria [$M$]. Esta memoria será el conjunto libremente generado por [$$M::= \emptyset \mid M,m\Leftarrow c$$] Los identificadores [$m$] son las direcciones de memoria y los objetos sintácticos [$c$] son las celdas con el contenido de esa dirección. Veremos la sintaxis de las celdas más abajo.&lt;br /&gt;&lt;br /&gt;Usaremos también los identificadores [$E$] como sinónimos a [$m$]. No son una nueva categoría, son la misma categoría sintáctica. Simplemente, vamos a usar [$E$] cuando hablemos de posiciones de memoria que guardan entornos. Esto nos hará mucho más legibles las ecuaciones y reglas a continuación.&lt;br /&gt;&lt;br /&gt;Si bien recuerda el lector de la primera parte, esta definición de [$M$] es muy similar a la definición de contexto [$C$] que teníamos. Esta vez, nuestro contexto no podrá tener valores porque todo hemos de guardarlo en la memoria para que pueda ser modificado. Así pues, nuestro contexto ahora será [$$C::=\emptyset \mid C,x\leftarrow m$$] Donde [$x$] son los identificadores de variable.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Operaciones sobre memoria y contextos&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Debido a la similitud entre la sintaxis de memoria y contexto, vamos a dar sus operaciones a la vez. La primera operación es el dominio que nos indica qué posiciones de memoria o qué identificadores de variable están en uso.&lt;br /&gt;&lt;br /&gt;En primer lugar, la memoria vacía o el contexto vacío tienen un dominio vacío.&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$$dom(\emptyset)=\emptyset$$]&lt;/td&gt;&lt;td&gt;[$$dom(\emptyset)=\emptyset$$]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Para continuar, el dominio de la memoria o el contexto más una asignación de memoria o vinculación de variable se calcula recursivamente.&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$$dom(M,m\Leftarrow c)=dom(M)\cup\{m\}$$]&lt;/td&gt;&lt;td&gt;[$$dom(C,x\leftarrow m)=dom(C)\cup\{x\}$$]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;La siguiente operación que vamos a especificar es la pertenencia a memoria o a contexto. El caso base es cuando la propia asignación o vinculación está en la parte más externa de la memoria o contexto.&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$$(m\Leftarrow c)\in(M,m\Leftarrow c)$$]&lt;/td&gt;&lt;td&gt;[$$&amp;nbsp; (x\leftarrow m)\in(M,x\leftarrow m) &amp;nbsp;$$]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;El caso recursivo ocurre cuando no se encuentra en esa posición externa.&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$$\frac{m\ne m'\;\;\;\;\;\;&amp;nbsp; (m\Leftarrow c)\in M}{(m\Leftarrow c)\in(M,m'\Leftarrow c')}$$]&lt;/td&gt;&lt;td&gt;[$$\frac{x\ne x'\;\;\;\;\;\;(x\leftarrow c)\in C}{(x\leftarrow m)\in(C,x'\leftarrow m')}$$]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Finalmente, y dado que estamos hablando de mutaciones de memoria, tendremos que introducir las operaciones de cambio de memoria y de contexto. Es similar a la pertenencia, pero con una comprobación extra por si la dirección de memoria o variable que queremos modificar no está usada y, por tanto, hay que añadirla. Empecemos por esta regla extra.&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$$\frac{m\notin dom(M)}{M\langle m\Leftarrow c\rangle=M,m\Leftarrow c}$$]&lt;/td&gt;&lt;td&gt;[$$&amp;nbsp; \frac{x\notin dom(C)}{C\langle x\leftarrow m\rangle=C,x\leftarrow m}$$]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&amp;nbsp;Cuando lo que queremos cambiar sí está en el dominio, hemos de buscarlo y cambiarlo. &lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$$(M,m\Leftarrow c)&amp;nbsp; \langle m\Leftarrow c'\rangle= (M,m\Leftarrow c') $$]&lt;/td&gt;&lt;td&gt;[$$&amp;nbsp; (M,x\leftarrow m) &amp;nbsp; \langle x\leftarrow m'\rangle = &amp;nbsp; (M,x\leftarrow m') &amp;nbsp;&amp;nbsp; $$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$$\frac{m\ne m'\;\;\;\;\;\;&amp;nbsp; m' \in dom(M)}{&amp;nbsp; (M,m\Leftarrow c)\langle m'\Leftarrow c' \rangle = &amp;nbsp; (M \langle m'\Leftarrow c' \rangle ,m\Leftarrow c) &amp;nbsp;}$$]&lt;/td&gt;&lt;td&gt;[$$\frac{x\ne x'\;\;\;\;\;\; x'\in dom(C)}{(C,x\leftarrow m)\langle x'\leftarrow m'\rangle = &amp;nbsp; (C \langle x'\leftarrow m'\rangle ,x\leftarrow m) &amp;nbsp;&amp;nbsp;}$$]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Celdas y entornos&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Las celdas van a contener los valores del LISP funcional. Además, dado que las vinculaciones de variables van a poder ser modificadas, también vamos a introducir en ellas a los contextos. Su sintaxis es la que sigue [$$c::= l \mid x \mid (m.m) \mid \lambda^Emm \mid |p| \mid C $$] Es decir, que una celda podrá ser o bien un literal [$l$], o bien una variable [$x$], o bien un par [$(m.m)$], o bien una clausura [$\lambda^Emm$], o bien un valor predefinido [$|p|$], o bien un contexto [$C$]. Recordemos que la [$E$] no es más que una dirección de memoria como las [$m$].&lt;br /&gt;&lt;br /&gt;Dentro de los literales incluimos la lista vacía que escribiremos [$()$]. Una lista de contextos es un entorno. La operación más importante en los entornos es la búsqueda de la vinculación de una variable. Lo haremos buscando en el contexto en posición de cabeza de la lista y luego, si no se encuentra, usando la recursión en el resto de la lista. Bastan dos reglas para realizar este procedimiento.&amp;nbsp; &lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$$\frac{E\Leftarrow(m'.E')\in M\;\;\;\;\;\;m'\Leftarrow C\in M\;\;\;\;\;\;x\leftarrow m\in C}{x\leftarrow m\in_M E}$$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$$\frac{&amp;nbsp; E\Leftarrow(m'.E')\in M\;\;\;\;\;\;m'\Leftarrow C\in M\;\;\;\;\;\;x\leftarrow m\notin C \;\;\;\;\;\; &amp;nbsp;x \leftarrow m \in_M E' }{ x\leftarrow m\in_M E }$$]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Las dos reglas de arriba son muy similares. Primero, en ambas reglas, se comprueba que la dirección de memoria [$E$] sea un par y que su primer campo [$m'$] apunte a un contexto [$C$]. Luego, si encontramos la variable en [$C$], ahí está (primera regla) y, si no la encontramos, buscamos en el resto de la lista [$E'$] que es el llamado entorno padre (segunda regla).&lt;br /&gt;&lt;br /&gt;Otra operación muy simple, y que más que nada es una abreviatura, es la introducción de un nuevo contexto en un entorno.[$$\frac{m' \notin dom(M)\cup\{m\}}{M\triangleright E\Leftarrow C\mid E' \triangleright M,m'\Leftarrow C, E\Leftarrow (m',E')}$$] Para empezar, usaremos [$M\triangleright$] a la izquierda y [$\triangleright M'$] a la derecha de un juicio cuando quiera indicar que la memoria [$M$] se cambia y como resultado obtenemos la memoria [$M'$]. En este caso, leemos el consecuente como "dada la memoria [$M$], obtengo el entorno [$E$] al introducir un nuevo contexto [$C$] en el entorno padre [$E'$] y la memoria con estos cambios es todo lo que hay a la derecha del [$\triangleright$]".&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;Relaciones auxiliares de evaluación&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En la primera parte introdujimos un par de relaciones auxiliares de evaluación: la desestructuración o ajuste de patrones y el envoltorio. Hemos de adaptar ambas a la introducción de la memoria. Ahora hemos de explorar la memoria en vez de explorar valores. Todo esto hace las reglas un poco más largas, pero en el fondo son exactamente las mismas.&lt;br /&gt;&lt;br /&gt;El ajuste de patrones sigue teniendo tres reglas: para literales (la llamaremos P-LIT), para variables (P-VAR) y para pares (P-PAIR).&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$$\frac{m\Leftarrow l\in M\;\;\;\;\;\;m'\Leftarrow l\in M}{C\{m\mid m'\}_M=C}$$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$$\frac{m\Leftarrow x\in M\;\;\;\;\;\; x\notin dom(C)}{C\{m\mid m'\}_M=(C,x\leftarrow m')}$$]&lt;/td&gt;&lt;/tr&gt;&amp;nbsp;&lt;tr&gt;&lt;td&gt;[$$\frac{m\Leftarrow (m_1.m_2)\in M\;\;\;\;\;\;m'\Leftarrow (m'_1.m'_2)\in M}{C\{m\mid m'\}_M=&amp;nbsp; C\{m_1\mid m'_1\}_M &amp;nbsp; \{m_2\mid m'_2\}_M  &amp;nbsp; }$$]&lt;/td&gt;&lt;/tr&gt;&amp;nbsp;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;El envoltorio sigue teniendo sus dos reglas: para la lista vacía (la llamaremos W-EMPTY) y para el par (W-PAIR). Esta vez se complica un poco más porque hemos de acarrear las memorias de una evaluación a la siguiente. De esta forma los cambios en la primera evaluación afectan a la segunda evaluación.&amp;nbsp; &lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$$\frac{m\Leftarrow ()\in M}{M\triangleright E \vdash m \Downarrow m \triangleright M}$$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$$\frac{m\Leftarrow (m_1.m_2)\in M\;\;\;\;\;\; M\triangleright E \vdash m_1 \downarrow m_1' \triangleright M_1 \;\;\;\;\;\; &amp;nbsp;&amp;nbsp; M_1\triangleright E \vdash m_2 \Downarrow m_2' \triangleright M_2 \;\;\;\;\;\;\; m' \notin dom(M_2) &amp;nbsp;}{&amp;nbsp; M\triangleright E \vdash m \Downarrow m' \triangleright M_2,m'\Leftarrow(m'_1.m'_2) } $$]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&amp;nbsp;En definitiva, lo que hace el envoltorio es evaluar los operandos para obtener los argumentos. En el proceso crea una lista de argumentos.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;La evaluación&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Ya tenemos todo lo necesario para la evaluación. Es exactamente igual que la evaluación en la versión funcional sólo que acarreando memorias de una evaluación a la siguiente y usando entornos en vez de contextos.&lt;br /&gt;&lt;br /&gt;&lt;table style="width: 100%;"&gt;&amp;nbsp; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$$\frac{m\Leftarrow l\in M}{M\triangleright E\vdash m\downarrow m \triangleright M}$$]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;La primera regla, que sigue siendo E-LIT, mira lo que hay en la dirección de memoria [$m$] y, si es un literal [$l$], devuelve la propia dirección de memoria como su resultado. Eso significa que el resultado de evaluar un literal es él mismo.&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$$&amp;nbsp; \frac{m\Leftarrow x\in M\;\;\;\;\;\; x\leftarrow m'\in_M E}{M\triangleright E \vdash m \downarrow m' \triangleright M} &amp;nbsp;$$]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Esta segunda regla, E-VAR, mira lo que hay en la dirección de memoria y, si es una variable [$x$], busca su vinculación [$m'$] en el entorno [$E$] y devuelve esa vinculación. En ninguna de estas dos reglas se modifica la memoria.&lt;br /&gt;&lt;table style="width: 100%;"&gt;&amp;nbsp;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$$&amp;nbsp; \frac{\begin{array}{c}m\Leftarrow(m_1.m_2)\in M\;\;\;\;\;\;M\triangleright E\vdash m_1 \downarrow m'_1 \triangleright M_1 \;\;\;\;\;\; m'_1 \Leftarrow |p|\in M_1 \\ &amp;nbsp;M_1 \triangleright E \vdash |p|m_2 \rightarrow_\delta m'_2 \triangleright M' \end{array}}{&amp;nbsp; M\triangleright E \vdash m \downarrow m' \triangleright M' &amp;nbsp;} &amp;nbsp;$$]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;La regla E-PRE, que trata con los valores predefinidos, es algo más compleja. Primero, la regla observa que [$m$] apunta a un par [$(m_1.m_2)$] en la memoria. Eso significa que hay una combinación y hemos de evaluarla. Evalúa el operador [$m_1$] y observa que su resultado [$m'_1$] apunta a un valor predefinido [$|p|$]. Además, hemos modificado la memoria al evaluar el operador y hemos de buscar en [$M_1$]. Una vez que sabemos que es un valor predefinido, delegamos toda evaluación a la relación delta [$\rightarrow_\delta$] que se encarga de los valores predefinidos. La especificaremos más adelante. &lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$$ \frac{&amp;nbsp; \begin{array}{c}m\Leftarrow(m_1.m_2)\in M\;\;\;\;\;\;M\triangleright E\vdash m_1 \downarrow m'_1 \triangleright M_1 \;\;\;\;\;\; m'_1 \Leftarrow \lambda^{E_c}m_f m_b\in M_1 \\ M_1 \triangleright E \vdash m_2 \Downarrow m'_2 \triangleright M_2 \;\;\;\;\;\; &amp;nbsp;M_2 \triangleright E' \Leftarrow \emptyset\{m_f \mid m'_2 \}_{M_2} \mid E_c \triangleright M_3 \;\;\;\;\;\; &amp;nbsp;M_3 \triangleright E' \vdash m_b \downarrow m' \triangleright M' \end{array}}{ M\triangleright E \vdash m \downarrow m' \triangleright M' } $$]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&amp;nbsp;La última regla, E-APP, es la más compleja y usa prácticamente todas las relaciones auxiliares vistas hasta ahora. Explicaremos lo que hace paso a paso:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;div&gt;Los tres primeros antecedentes son exactamente iguales que los de la regla E-PRE. Es decir, comprobamos que es un par, evaluamos el primer componente y descubrimos que es, en este caso, una clausura con entorno de clausura en la dirección de memoria [$E_c$] con parámetros formales en la dirección de memoria [$m_f$] y el código a ejecutar en la dirección de memoria [$m_b$].&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div&gt;A continuación, evaluamos los operandos para obtener los argumentos. Esto es justamente lo que hace la relación de envoltorio. Es el primer antecedente de la segunda fila.&lt;/div&gt;&lt;/li&gt;&lt;li&gt;Una vez que tenemos los argumentos, usamos ajuste de patrones para generar un contexto en el cual estén vinculadas las variables de los parámetros formales [$m_f$] a los argumentos [$m'_2$]. Esta parte es [$\emptyset\{m_f\mid m'_2\}_{M_2}$].&lt;/li&gt;&lt;li&gt;Luego, ese contexto se introduce en un nuevo entorno [$E'$] usando como entorno padre el [$E_c$] para obtener la memoria [$M_3$]. Es lo que hace [$ M_2 \triangleright E' \Leftarrow \emptyset\{m_f \mid m'_2 \}_{M_2} \mid E_c \triangleright M_3 $]&lt;/li&gt;&lt;li&gt;Entonces, tenemos en la dirección de memoria [$E'$] el entorno donde evaluar el cuerpo de la clausura y obtener el resultado [$m'$] junto con la memoria final [$M'$]. Es lo que hace el último antecedente.&lt;/li&gt;&lt;/ol&gt;Para ver cómo funciona todo esto, haremos un ejemplo de evaluación.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Ejemplo de evaluación&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Aunque va a ser un ejemplo muy simple, la memoria va a estar bastante llena. Para no liarnos voy a usar como identificadores de memoria los valores de la semántica funcional entre corchetes. De esta forma entendemos mejor qué hay en la dirección de memoria [$m_4$] si en vez de escribir [$m_4$] escribo [$[\lambda^{C_0}((x.y))x]$].&lt;br /&gt;&lt;br /&gt;Entonces, nuestra memoria [$M_0$] va a ser la siguiente.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$[C_0]$]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$list\leftarrow [\lambda^{(C_0)}xx], car\leftarrow [\lambda^{(C_0)}((x.y))x] $]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [\lambda^{(C_0)}xx] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$ \lambda^{[(C_0)]}[x][x]$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [x] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$x$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [\lambda^{(C_0)}((x.y))x] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$\lambda^{[(C_0)]}[((x.y))][x]$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [((x.y))] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$([(x.y)].[()])$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [(x.y)] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$([x].[y])$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [y] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$y$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [(car\ (list\ 1\ 2))] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$([car].[((list\ 1\ 2))])$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [car] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$car$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [((list\ 1\ 2))] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$([(list\ 1\ 2)].[()])$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [(list\ 1\ 2)] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$([list].[(1\ 2)])$]&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [()] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$()$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [list] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$list$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [(1\ 2)] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$([1].[(2)])$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [1] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$1$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [(2)] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$([2].[()])$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [2] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$2$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$ [(C_0)] $]&lt;/td&gt;&lt;td&gt;[$\Leftarrow$]&lt;/td&gt;&lt;td&gt;[$([C_0].[()])$]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Ahora vamos a querer evaluar la dirección de memoria [$m=[(car\ (list\ 1\ 2))]$] en el entorno [$E_0=[(C_0)]$] y usando la memoria [$M_0$]. Necesitaremos hallar los interrogantes de [$$ M_0\triangleright E_0 \vdash m \downarrow\ ????\ \triangleright\ ????$$] Deberemos proceder con la regla E-APP en la cual encontramos que [$[(car\ (list\ 1\ 2))]\Leftarrow ([car].[((list\ 1\ 2))])\in M_0$] Entonces, [$m_1=[car]$] y hemos de evaluar [$$ M_0 \triangleright E_0 \vdash m_1 \downarrow\ ????\ \triangleright\ ????$$] Hay que aplicar la regla E-VAR en la cual obtenemos como resultado la dirección de memoria [$[\lambda^{(C_0)}((x.y))(x)]$]. &lt;br /&gt;&lt;br /&gt;A continuación hemos de realizar el envoltorio. Aparcamos E-APP(car). Ahora, como [$[((list\ 1\ 2))]\Leftarrow ([(list\ 1\ 2).[()]) \in M_0$] es un par, hay que entrar en W-PAIR. Nos dice que evaluemos el primer componente del par que es[$[(list\ 1\ 2)]$]. Tendremos que usar E-APP otra vez.&lt;br /&gt;&lt;br /&gt;Aparcamos W-PAIR(car) y E-APP(car) para entrar en E-APP(list). Como [$[(list\ 1\ 2)]\Leftarrow ([list].[(1\ 2)]) \in M_0$], la regla E-APP me dice que evalúe el primer componente del par. En este caso [$[list]$]. Aplicando E-VAR obtenemos que el resultado es la celda [$\lambda^{[(C_0)]}[x][x]$] y tengo que entrar en envoltorio otra vez.&lt;br /&gt;&lt;br /&gt;Tenemos en suspenso E-APP(list), W-PAIR(car) y E-APP(car). Y estamos trabajando con W-PAIR para envolver [$[(1\ 2)]\Leftarrow ([1].[(2)])\in M_0$]. Esta regla me dice que evalúe el primer componente que por E-LIT es él mismo [$[1]$] y que vuelva a aplicar el envoltorio sobre el segundo componente [$[(2)]$]. Aparco este W-PAIR(1) y voy con W-PAIR otra vez.&lt;br /&gt;&lt;br /&gt;En este punto están en suspenso W-PAIR(1), E-APP(list), W-PAIR(car) y E-APP(car). Seguimos trabajando con la memoria [$M_0$] y hemos de aplicar W-PAIR a [$[(2)]\Leftarrow ([2].[()])\in M_0$]. El resultado es que [$[2]$] se evalúa por E-LIT a él mismo y W-EMPTY me devuelve el propio [$[()]$].&lt;br /&gt;&lt;br /&gt;Ahora ocurre una cosa muy importante. La regla W-PAIR modifica la memoria. Añade un par en una nueva dirección. El primer componente del par es el resultado de la evaluación del primer componente, que era [$[2]$] y el segundo, el del envoltorio, que era [$[()]$]. Entonces, mi nueva memoria será [$$M_1=M_0,m_0\Leftarrow ([2].[()])$$] y el resultado de W-PAIR es [$$ M_0 \triangleright E_0 \vdash [(2)] \Downarrow m_0 \triangleright M_1$$] Este cambio de memoria es importante porque ahora recuperamos W-PAIR(1) y usa [$M_1$] en vez de [$M_0$].&lt;br /&gt;&lt;br /&gt;Nota: Escribo [$m_0$] en vez de [$[(2)]$] porque [$[(2)]$] ya está usado en [$M_0$] y se confundiría. Tenemos dos celdas con el mismo contenido en memoria.&lt;br /&gt;&lt;br /&gt;Retomamos W_PAIR(1) y sigue en suspenso E-APP(list), W-PAIR(car) y E-APP(car). La regla W_PAIR vuelve a modificar la memoria. En este caso [$$M_2=M_1,m_1\Leftarrow ([1].m_0)$$] y lo que hemos demostrado es [$$ M_0 \triangleright E_0 \vdash [(1\ 2)] \Downarrow m_1 \triangleright M_2$$].&lt;br /&gt;&lt;br /&gt;Retomamos E-APP(list) y sigue en suspenso W-PAIR(car) y E-APP(car). El siguiente antecedente de la regla E-APP es el que realiza el ajuste de patrones. En este caso hemos de ajustar [$\emptyset\{[x]\mid m_2\}_{M_2}$]. Es sencillo usando la regla P-VAR. El ajuste devuelve el contexto [$C_1=x\leftarrow m_2$].&lt;br /&gt;&lt;br /&gt;A continuación, la regla E-APP introduce el nuevo contexto [$C_1$] en la memoria. La nueva memoria es [$$M_3=M_2, [C_1]\Leftarrow C_1, [(C_1 C_0)]\Leftarrow ([C_1].[(C_0)]$$] y el nuevo entorno está en [$[(C_1 C_0)]$]. En este nuevo entorno y con esta nueva memoria evaluamos el cuerpo de la clausura que era [$[x]$]. Usamos para ello la regla E-VAR y encontramos que [$x\leftarrow m_2 \in_{M_3} [(C_1 C_2)]$] por lo que el resultado es [$m_2$] con la propia memoria [$M_3$]. Entonces lo que hemos demostrado hasta ahora es que [$$ M_0 \triangleright E_0 \vdash [(list\ 1\ 2)] \downarrow m_2 \triangleright M_3 $$]&lt;br /&gt;&lt;br /&gt;Retomemos W-PAIR(car) y mantengamos en suspenso E-APP(car). La regla W-PAIR, tras evaluar el primer componente del par, envuelve el segundo. Usando la regla W-EMPTY obtenemos [$[()]$] como resultado de este envoltorio. A continuación, modifica la memoria incluyendo un nuevo par en [$m_3$] con ambos resultados. Es decir que [$M_4=M_2,m_3\Leftarrow (m_2.[()])$] y hemos demostrado que [$$ M_0 \triangleright E_0 \vdash [((list\ 1\ 2))] \Downarrow m_3 \triangleright M_4$$]&lt;br /&gt;&lt;br /&gt;Retomamos, por fin, E-APP(car). Hemos de realizar primero el ajuste de patrones en el cual obtenemos el contexto [$C_2=x\leftarrow [1],y\leftarrow m_1$]. Luego, incluimos un nuevo entorno en la memoria con ese contexto y con entorno padre el de la clausura. [$$M_5=M_4, [C_2]\Leftarrow C_2, [(C_2 C_0)]\Leftarrow ([C_2].[(C_0)])$$] Y, finalmente, evaluamos el cuerpo de la clausura. Es sencillo porque consta únicamente de una variable y aplicamos E-VAR. Demostramos, por fin, que [$$M_0 \triangleright E_0 \vdash [(car\ (list\ 1\ 2))] \downarrow [1] \triangleright M_5$$]&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;Valores predefinidos y formas especiales&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Especificaremos muy pocas formas predefinidas. La más usual en un lenguaje imperativo es la evaluación en secuencia. Usaremos el valor predefinido [$|begin|$] para esta evaluación. Necesitamos tres reglas. La primera dice que la evaluación en secuencia de la lista vacía es la propia lista vacía.[$$\frac{m\Leftarrow ()\in M}{M\triangleright E \vdash |begin|m \rightarrow_\delta m \triangleright M}$$] La segunda regla indica que si la lista a evaluar en secuencia sólo tiene un elemento, el resultado es la evaluación de ese elemento. [$$\frac{m\Leftarrow (m_1.m_2)\in M \;\;\;\;\;\; m_2\Leftarrow () \in M \;\;\;\;\;\; M \triangleright E \vdash m_1 \downarrow m' \triangleright M'}{M\triangleright E \vdash m \rightarrow_\delta m' \triangleright M'}$$]Finalmente, si hay más de un elemento, evaluamos el primero y evaluamos en secuencia el resto.[$$\frac{m\Leftarrow (m_1.m_2)\in M \;\;\;\;\;\; m_2\Leftarrow () \notin M \;\;\;\;\;\; M \triangleright E \vdash m_1 \downarrow m'_1 \triangleright M_1 \;\;\;\;\;\; M_1 \triangleright E \vdash |begin|m_2 \rightarrow_\delta m' \triangleright M'}{M\triangleright E \vdash m \rightarrow_\delta m' \triangleright M'}$$]&lt;br /&gt;&lt;br /&gt;Para definir una vinculación usamos el valor predefinido [$|def!|$].[$$\frac{m\Leftarrow (m_1.m_2) \in M \;\;\;\;\;\; m_1 \Leftarrow x \in M \;\;\;\;\;\; M \triangleright E \vdash |begin|m_2 \rightarrow_\delta m' \triangleright M'}{ M\triangleright E \vdash |def!|m \rightarrow_\delta m' \triangleright M' \langle E \Leftarrow x \leftarrow m'\rangle}$$] La relación auxiliar [$M \langle E \Leftarrow x \leftarrow m\rangle$] es la que realmente modifica la memoria con la nueva definición.[$$\frac{E\Leftarrow (m_1.E_2)\in M \;\;\;\;\;\; m_1 \Leftarrow C \in M}{M \langle E \Leftarrow x \leftarrow m\rangle = M\langle M_1 \Leftarrow C \langle x \leftarrow m \rangle \rangle}$$]&lt;br /&gt;&lt;br /&gt;Es posible definir el valor predefinido [$|set!|$] que modifica una vinculación preexistente. La dificultad de esta definición estriba en hacerla recursiva (hacia el entorno padre) si no se halla la variable a modificar en el contexto actual.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-1795239566474208859?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/1795239566474208859/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/11/semantica-natural-de-lisp-parte-2-lisp.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/1795239566474208859'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/1795239566474208859'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/11/semantica-natural-de-lisp-parte-2-lisp.html' title='Semántica natural de LISP - parte 2 - LISP imperativo'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-5328742831335951498</id><published>2011-10-28T13:02:00.001+02:00</published><updated>2011-10-28T13:03:03.097+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='teoria de tipos'/><category scheme='http://www.blogger.com/atom/ns#' term='lenguajes de programación'/><category scheme='http://www.blogger.com/atom/ns#' term='matemáticas'/><category scheme='http://www.blogger.com/atom/ns#' term='semántica formal'/><title type='text'>El combinador Y en C++ (y II)</title><content type='html'>La primera parte de esta serie está &lt;a href="http://elmanantialdebits.blogspot.com/2009/08/el-combinador-y-en-c-i.html"&gt;aquí&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Como se comentó en la primera parte, el combinador Y toma una función g que representa un paso de recursión y devuelve una función p que es el punto fijo de g. Esto del punto fijo no es más que la función recursiva obtenida aplicando g a sí misma infinitas veces. El problema con este planteamiento es que currificar en C++ es difícil. Por esta razón usaremos una versión de g que no esté currificada. El prototipo de esta función sería:&lt;br /&gt;&lt;pre class="brush:cpp"&gt;#include &amp;lt;functional&amp;gt;&lt;br /&gt;&lt;br /&gt;int g(std::function&amp;lt;int(int)&amp;gt; f,int v);&lt;/pre&gt;El tipo de los objetos función en C++ es muy largo y escribir "std::function" cada vez va a emborronar el código. Usaré una macro para aligerar la notación.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;#include &amp;lt;functional&amp;gt;&lt;br /&gt;&lt;br /&gt;//F(X,Y) es X-&amp;gt;Y&lt;br /&gt;#define F(X,Y) std::function&amp;lt;Y(X)&amp;gt;&lt;br /&gt;&lt;br /&gt;//F(X,Y,Z) es (X,Y)-&amp;gt;Z&lt;br /&gt;#define F2(X,Y,Z) std::function&amp;amp;lg;Z(X,Y)&amp;gt;&lt;br /&gt;&lt;br /&gt;int g(F(int,int) f,int v);&lt;/pre&gt;Ahora vamos a tratar de definir el combinador Y. La mejor forma de hacerlo es, en vez de usar las funciones lambda de C++ que son muy tediosas, usando la ecuación recursiva que obtuvimos en la primera parte.&lt;br /&gt;&lt;br /&gt;Y(g)=g(Y(g))&lt;br /&gt;&lt;br /&gt;Como ahora tengo a g sin currificar, he de añadir un argumento extra. Queda así:&lt;br /&gt;&lt;br /&gt;Y(g)=[](x){g(Y(g),x)}&lt;br /&gt;&lt;br /&gt;Entonces, el código del combinador Y para los enteros sería&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;F(int,int) Y(  F2( F(int,int) ,int,int)  f)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;   return [=](int x){return f(Y(f),x);};&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Realmente la parte difícil es la de los tipos, aunque se pueden obtener poco a poco estudiando la expresión.&lt;br /&gt;&lt;br /&gt;Cambiar los int por un tipo genérico nos da el combinador Y genérico en C++:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;template&amp;lt;typename T&amp;gt;&lt;br /&gt;F(T,T) Y(  F2( F(T,T) ,T,T)  f)&lt;br /&gt;{&lt;br /&gt;    return [=](T x){return f(Y(f),x);};&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Ahora sólo tenemos que usarlo. Definimos para eso la función g del factorial y lo volcamos a la salida. El código final es el que sigue:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;#include &amp;lt;functional&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;//F(X,Y) es X-&amp;gt;Y&lt;br /&gt;#define F(X,Y) std::function&amp;lt;Y(X)&amp;gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;//F(X,Y,Z) es (X,Y)-&amp;gt;Z&lt;br /&gt;#define F2(X,Y,Z) std::function&amp;amp;lg;Z(X,Y)&amp;gt;&lt;br /&gt;&lt;br /&gt;int g(F(int,int) f,int v)&lt;br /&gt;{&lt;br /&gt;    return v==0 ? 1 : v * f(v-1);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;template&amp;lt;typename T&amp;gt;&lt;br /&gt;F(T,T) Y(  F2( F(T,T) ,T,T)  f)&lt;br /&gt;{&lt;br /&gt;    return [=](T x){return f(Y(f),x);};&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(int argc,char** argv)&lt;br /&gt;{&lt;br /&gt;std::cout &amp;lt;&amp;lt; Y&amp;lt;int&amp;gt;(g)(5) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;En este punto sólo queda advertir al lector que es necesario usar un compilador compatible con el estándar de C++ de 2011.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-5328742831335951498?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/5328742831335951498/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/10/el-combinador-y-en-c-y-ii.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/5328742831335951498'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/5328742831335951498'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/10/el-combinador-y-en-c-y-ii.html' title='El combinador Y en C++ (y II)'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-872340692747763477</id><published>2011-10-27T13:12:00.004+02:00</published><updated>2011-11-04T13:30:20.543+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='LISP'/><category scheme='http://www.blogger.com/atom/ns#' term='semántica formal'/><title type='text'>Semántica natural de LISP - parte 1 - LISP funcional</title><content type='html'>Como homenaje a &lt;a href="http://elmanantialdebits.blogspot.com/2011/10/muere-john-mccarthy.html"&gt;McCarthy&lt;/a&gt;, voy a dedicar una serie de posts a descubrir la semántica natural del LISP. Empezaremos por un LISP reducido que llamaré LISP funcional en el cual no hay mutaciones de las vinculaciones de variables. Cualquiera que haya leído el &lt;a href="http://mitpress.mit.edu/sicp/full-text/book/book.html"&gt;SICP&lt;/a&gt; reconocerá que ésto se corresponde a la primera parte del libro.&lt;br /&gt;&lt;br /&gt;La &lt;a href="http://fi.uaemex.mx/rmarcial/FundLengProg/Clase4.pdf"&gt;semántica natural o semántica de paso grande&lt;/a&gt; no es más que una relación que a cada programa [$t$] en un contexto [$C$] le proporciona un valor [$v$]. Escribiremos esta relación así [$$C \vdash t \downarrow v$$] y se lee "[$t$] se evalúa a [$v$] bajo el contexto [$C$]". Aunque antes debemos especificar claramente cuáles son las estructuras sintácticas que forman [$t$], [$C$] y [$v$].&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Sintaxis&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;La sintaxis de los programas son términos [$t$] que son a su vez, o bien una variable [$x$], o bien un literal [$l$], o bien un par de términos [$(t.t)$]. Esto se escribe así: [$$t ::= x \mid l \mid ( t . t )$$] Dentro de los literales incluimos la lista vacía [$()$] que permite, junto con el par, formar listas. Una lista [$(1 2 3)$] es realmente [$(1.(2.(3.())))$]. Es decir, el primer componente del par es el término que está en la cabeza de la lista y el segundo componente es otra lista que representa al resto de los términos. Es común llamar a estos componentes "head" y "tail" &amp;nbsp;(cabeza y cola en inglés) o "car" y "cdr". Estos dos últimos nombres tienen una &lt;a href="http://www.iwriteiam.nl/HaCAR_CDR.html"&gt;historia más larga&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Los literales son símbolos como [$1, 53, "hola",$] etc. que tienen un valor en sí mismos. Las variables son símbolos como [$x, y, z,$] etc. que requieren un contexto para saber el valor que representan.&lt;br /&gt;&lt;br /&gt;La sintaxis de los valores [$v$] es o bien un término [$t$], o bien una clausura [$\lambda ^C t t$], o bien una forma predefinida [$|p|$]. [$$v::=t\mid \lambda^C tt \mid |p|$$] Escribiremos las formas predefinidas entre barras para distinguirlas de las variables y literales, aunque el símbolo que sea [$p$] puede coincidir con ellos.&lt;br /&gt;&lt;br /&gt;Los contextos no son más que una colección de vinculaciones de valores a variables.[$$ C::= \emptyset \mid C,x\leftarrow v$$] Construímos los contextos con el contexto vacío [$\emptyset$] al que le vamos agregando vinculaciones de la forma [$x\leftarrow v$]. Aunque la forma correcta de escribir un contexto sea [$\emptyset, x \leftarrow 5, y \leftarrow 8$], omitiremos el [$\emptyset$].&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;Operaciones sobre contextos&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Vamos a necesitar un par de operaciones para trabajar con los contextos. Son muy simples. La primera es el dominio del contexto [$dom\ C$] que nos dice qué variables se han usado en un contexto. [$$ dom\ \emptyset = \emptyset $$][$$ dom(C,x\leftarrow v)=dom(C)\cup\{x\}$$]&lt;br /&gt;&lt;br /&gt;La segunda operación busca una variable en un contexto. Lo escribiremos como una relación de pertenencia [$x\leftarrow v \in C$] para simplificar la lectura. [$$x\leftarrow v\in C,x\leftarrow v$$][$$\frac{x\ne x'\;\;\;\;\;\;x\leftarrow v\in C}{x\leftarrow v\in C,x'\leftarrow v'}$$]La primera línea es una regla tan obvia que lo mismo es difícil de entender: [$x\leftarrow v$] pertenece a [$C,x\leftarrow v$]. La segunda regla dice que [$x\leftarrow v$] pertenece a [$C,x'\leftarrow v'$] si [$x$] es distinta a [$x'$] y [$x\leftarrow v$] pertenece a [$C$]. Si llega un momento que [$C=\emptyset$], no podremos usar ninguna de las dos reglas (y por tanto [$x\leftarrow v$] no pertenecerá).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Ajuste de patrones&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Llegará un momento en la evaluación en el cual tendremos que relacionar &lt;a href="http://elmanantialdebits.blogspot.com/2009/10/argumentos-y-parametros.html"&gt;argumentos con parámetros&lt;/a&gt;. La forma más inteligente de hacerlo es usando &lt;a href="http://en.wikipedia.org/wiki/Destructuring_assignment"&gt;el ajuste de patrones, también llamado asignación desestructurante&lt;/a&gt;. El ajuste de patrones que vamos a ver aquí es muy simple: toma un término y un valor, devolviendo las vinculaciones que deberían tener las variables del término para que se ajuste al valor proporcionado. Por ejemplo. Si quiero ajustar [$x$] y [$3$], lo escribiré así [$\{x\mid 3\}$] y el resultado será que la variable [$x$] ha de vincularse al valor [$3$]. Esta vinculación es la que hemos escrito [$x\leftarrow 3$] en los contextos. Como no tenemos contexto al que añadir la vinculación, lo incluiremos en nuestro ajsute de patrones. El resultado es que el ajuste de patrones es una relación [$C\{t\mid v\}=C$]. El ejemplo de arriba se podría completar entonces con [$$z\leftarrow 8\;\{x\mid 3\}=z\leftarrow 8,x\leftarrow 3$$]Más ejemplos serían [$$z\leftarrow 8\;\{(x\; y)\mid (3\;7)\}=&amp;nbsp; z\leftarrow 8,x\leftarrow 3,y\leftarrow 7$$][$$\emptyset\{(x y. z)\mid(1 \; (2 \; 3) \; 4 \; 5 \; 6)\}=x\leftarrow 1,y\leftarrow(2\;3), z\leftarrow(4&amp;nbsp; \;5&amp;nbsp; \; 6)$$][$$x\leftarrow 5\{x\mid 5\}=???$$] En el último ejemplo no es posible calcular el ajuste de patrones porque [$x$] ya está definida. ¡Incluso si le vamos a dar el mismo valor! De esta manera cada contexto sólo tendrá una única aparición de cada variable.&lt;br /&gt;&lt;br /&gt;Las reglas del ajuste de patrones son muy sencillas. En primer lugar, la regla D-LIT dice que los literales han de coincidir.[$$C\{l\mid l\}=C$$] La regla D-VAR modifica el contexto vinculando la variable, que no está definida previamente, al valor.[$$\frac{x\notin C}{C\{x\mid v\}=C,x\leftarrow v}$$] Finalmente, la regla D-PAIR es meramente estructural.[$$C\{(t_1.t_2)\mid(v_1.v_2)\}=C\{t_1\mid v_1\}\{t_2\mid v_2\}$$]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;La evaluación&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Llega la hora de dar la relación de evaluación [$C \vdash t \downarrow v$] que antes mencionábamos. Son cuatro reglas. La primera, que llamaremos E-LIT, es para saber el valor de un literal. Es muy sencillo porque es él mismo. [$$C \vdash l \downarrow l$$] La segunda (E-VAR) es para saber el valor de una variable. Necesitamos consultar el contexto.[$$\frac{x\leftarrow v \in C}{C \vdash x\downarrow v}$$] La tercera la usaremos para pares cuya cabeza se evalúe a un valor por predefinido. La llamaremos E-PRE. [$$\frac{C\vdash t_0 \downarrow |p|&amp;nbsp; \;\;\;\;\;\; C\vdash (|p| t_1 \cdots t_n) \rightarrow_\delta v}{C\vdash (t_0 t_1 \cdots t_n)\downarrow v}$$] Aquí hemos usado una relación auxiliar [$C\vdash v\rightarrow_\delta v$] en la que introduciremos la semántica de los valores predefinidos (ver más abajo). Finalmente, la regla E-APP, formaliza el uso de una clausura.[$$\frac{C\vdash t_0 \downarrow \lambda^{C'}t't''&amp;nbsp; \;\;\;\;\;\; C\vdash (t_1 \cdots t_n) \Downarrow (v_1 \cdots v_n) &amp;nbsp; \;\;\;\;\;\; &amp;nbsp;C' \{ t' \mid (v_1 \cdots v_n) \}\vdash t''\downarrow v}{C\vdash (t_0 t_1 \cdots t_n) \downarrow v}$$] Hemos usado el ajuste de patrones en el último antecedente (a la derecha del todo.) También hemos usado una relación auxiliar [$ C\vdash (t_1 \cdots t_n) \Downarrow (v_1 \cdots v_n)  $] que llamaremos de "envoltorio" que lo único que hace es evaluar una lista de términos, término a término, para obtener una lista de valores.&lt;br /&gt;&lt;br /&gt;Las reglas de esta relación auxiliar de envoltorio son muy simples. Primero, la lista vacía se envuelve a sí misma. [$$C\vdash () \Downarrow ()$$] Y segundo, un par evalúa su cabeza y envuelve el resto. [$$\frac{C\vdash t_1 \downarrow v_1&amp;nbsp;  \;\;\;\;\;\; C\vdash t_2 \Downarrow v_2}{C \vdash (t_1.t_2) \Downarrow (v_1.v_2)}$$] En general podemos ver la relación de envoltorio como una abreviatura de&lt;br /&gt;[$$C\vdash t_1 \downarrow v_1 &amp;nbsp; \;\;\;\;\;\; &amp;nbsp; &amp;nbsp; C\vdash t_2 \downarrow v_2 &amp;nbsp;&amp;nbsp;&amp;nbsp; \;\;\;\;\;\; &amp;nbsp;\cdots &amp;nbsp; \;\;\;\;\;\; &amp;nbsp; C\vdash t_n \downarrow v_n &amp;nbsp;$$] &amp;nbsp;que escribimos [$$ C\vdash (t_1t_2\cdots t_n) \Downarrow (v_1v_2\cdots v_n)$$]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Formas predefinidas&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Las formas predefinidas nos pueden servir para trabajar con los literales. Por ejemplo, la suma se puede formalizar así (llamaremos a esta regla P-ADD): [$$\frac{C\vdash (t_1 \cdots t_n)\Downarrow (N_1 \cdots N_n) }{&amp;nbsp; C\vdash (|+| t_1 \cdots t_n)\rightarrow_\delta \sum_{k=1}^n{N_k} &amp;nbsp;}$$] Donde los [$N$] mayúsculas han de ser literales de número como el [$3$] o el [$75.82$].&lt;br /&gt;&lt;br /&gt;Entre todas las formas es especialmente importante la que genera clausuras. Llamaremos a este valor predefinido[$|\lambda|$] y se define con la regla P-LAMBDA [$$C\vdash (|\lambda| t_1 t_2) \rightarrow_\delta \lambda^Ct_1 t_2 $$] Con esta &lt;a href="http://www.nhplace.com/kent/Papers/Special-Forms.html"&gt;forma especial&lt;/a&gt; podemos definir funciones.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;Ejemplos de evaluación&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Si usamos un contexto inicial [$$C_0 = lambda \leftarrow |\lambda|, +\leftarrow |+|$$] tenemos suficiente potencia expresiva para calcular el doble de [$3$] (realmente, con lambda y usando la &lt;a href="http://en.wikipedia.org/wiki/Church_encoding"&gt;codificación de Church&lt;/a&gt;, tenemos la potencia expresiva de un modelo computacional &lt;a href="http://es.wikipedia.org/wiki/Turing_completo"&gt;Turing completo&lt;/a&gt;). Me he tomado algunas libertades para simplificar la derivación (no he usado la abreviatura del envoltorio y le he dado nombres a los contextos). El resultado es el que sigue (clic para ampliar):&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-KkvmP0Rs1CE/Tqk6TMoz7jI/AAAAAAAAALE/3xwxxZFaY-U/s1600/DobleDe3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="40" src="http://2.bp.blogspot.com/-KkvmP0Rs1CE/Tqk6TMoz7jI/AAAAAAAAALE/3xwxxZFaY-U/s400/DobleDe3.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;En el contexto inicial podemos incluir más definiciones. Algunas funciones típicas son:[$$car\leftarrow \lambda^{C_0}((x.y))x$$][$$cdr\leftarrow\lambda^{C_0}((x.y))y$$][$$list\leftarrow\lambda^{C_0}xx$$][$$cons\leftarrow\lambda^{C_0}(x y)(x.y)$$] Con este nuevo contexto inicial podemos calcular el segundo elemento de la lista [$(1 2 3)$]. La derivación (omitiendo ya nombres de reglas) es la que sigue:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-NVNvQuiMwzE/Tqk63WivKnI/AAAAAAAAALM/N1LyIdFwjfM/s1600/SegundoElemento.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="36" src="http://4.bp.blogspot.com/-NVNvQuiMwzE/Tqk63WivKnI/AAAAAAAAALM/N1LyIdFwjfM/s400/SegundoElemento.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Hasta aquí por hoy. En la siguiente parte de esta serie permitiremos mutaciones en la vinculación de las variables.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-872340692747763477?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/872340692747763477/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/10/semantica-natural-de-lisp-parte-1-lisp.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/872340692747763477'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/872340692747763477'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/10/semantica-natural-de-lisp-parte-1-lisp.html' title='Semántica natural de LISP - parte 1 - LISP funcional'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-KkvmP0Rs1CE/Tqk6TMoz7jI/AAAAAAAAALE/3xwxxZFaY-U/s72-c/DobleDe3.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-4766495767533617887</id><published>2011-10-25T13:43:00.000+02:00</published><updated>2011-10-25T13:43:38.521+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='varios'/><title type='text'>Muere John McCarthy</title><content type='html'>Estamos teniendo un mes bastante triste en el mundo de la informática. Primero, muere el carismático Jobs, luego el creador del lenguaje C, &lt;a href="http://elmanantialdebits.blogspot.com/2011/10/muere-un-grande-de-la-informatica.html"&gt;Dennis Ritchie&lt;/a&gt;,&amp;nbsp; y ayer murió John McCarthy el creador del &lt;a href="http://en.wikipedia.org/wiki/Lisp_(programming_language)"&gt;LISP&lt;/a&gt; (en 1959) y casi todas las tecnologías asociadas a él, entre otras:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)"&gt;Recolección de basura&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Dynamic_typing#Dynamic_typing"&gt;Tipado dinámico&lt;/a&gt; y &lt;a href="http://en.wikipedia.org/wiki/Tree_data_structure"&gt;estructuras arborescentes para datos&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Homoiconicity"&gt;Homoiconicidad&lt;/a&gt; y &lt;a href="http://en.wikipedia.org/wiki/S-expression"&gt;expresiones S&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Abstracción de punteros&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Symbolic_computing"&gt;Computación simbólica&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/REPL"&gt;REPLs&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Self-hosting"&gt;Autocompiladores&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Modelo de evaluación por entornos&lt;/li&gt;&lt;/ul&gt;Además, leo que inventó la &lt;a href="http://en.wikipedia.org/wiki/Non-monotonic_logic"&gt;lógica no monótona&lt;/a&gt; por &lt;a href="http://en.wikipedia.org/wiki/Circumscription_(logic)"&gt;circunscripción&lt;/a&gt;. Esta lógica viene a decir más o menos que si no enciende el televisor, no enciende la tostadora, no enciende la nevera y no enciende la estufa, lo que fallan son los fusibles. Esto que parece una tontería es uno de los puntales en inteligencia artificial. Campo al que se dedicó en vida. Descanse en paz.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://upload.wikimedia.org/wikipedia/commons/thumb/4/49/John_McCarthy_Stanford.jpg/800px-John_McCarthy_Stanford.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="265" src="http://upload.wikimedia.org/wikipedia/commons/thumb/4/49/John_McCarthy_Stanford.jpg/800px-John_McCarthy_Stanford.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-4766495767533617887?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/4766495767533617887/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/10/muere-john-mccarthy.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/4766495767533617887'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/4766495767533617887'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/10/muere-john-mccarthy.html' title='Muere John McCarthy'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-1808796681891548319</id><published>2011-10-22T11:16:00.000+02:00</published><updated>2011-10-22T11:16:14.205+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='varios'/><title type='text'>El extraño caso del disco duro resucitado</title><content type='html'>Se me &lt;a href="http://www.pcguide.com/ref/hdd/perf/qual/issuesFailure-c.html"&gt;fastidió el disco duro&lt;/a&gt;. Es una lata perder varios gigas de información. Antiguamente, si se te rompía un &lt;a href="http://en.wikipedia.org/wiki/Floppy_disk"&gt;floppy&lt;/a&gt;, tampoco era un trauma. Eran 1.44 MB. La cosa ha cambiado. En la actualidad, cualquier fallo se lleva gigas y gigas por delante.&lt;br /&gt;&lt;br /&gt;Afortunadamente los discos duros suelen fallar por &lt;a href="http://static.googleusercontent.com/external_content/untrusted_dlcp/labs.google.com/es//papers/disk_failures.pdf"&gt;motivos mecánicos&lt;/a&gt;. Las piezas se van deformando poco a poco. Los encajes son cada vez menos perfectos. El rozamiento va limando lentamente las zonas de fricción. ¿Por qué digo afortunadamente? Porque los discos duros suelen empezar a hacer &lt;a href="http://datacent.com/hard_drive_sounds.php"&gt;ruidos raros&lt;/a&gt; antes de dejar de funcionar definitivamente. El mío, particularmente, además de los ruidos raros, dejaba de responder y se reiniciaba.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.hddkillers.com/blogstuff/070417/hardware/medium/open%20off.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://www.hddkillers.com/blogstuff/070417/hardware/medium/open%20off.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Así que, al primer ruido raro que oí, apagué el ordenador, desconecté el disco duro físicamente y empecé a buscar sustituto. Tras unos días de espera por el pedido (hace años que las tiendas de informática no tienen casi nada en stock), procedí a instalar el nuevo disco. Cada vez que me compro un disco nuevo es más silencioso, se calienta menos y tiene más capacidad. Es maravilloso. &lt;a href="http://www.pcworld.com/article/129558/study_hard_drive_failure_rates_much_higher_than_makers_estimate.html"&gt;Mientras no fallen, claro&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://filizefe.files.wordpress.com/2009/12/600px-hard_drive_capacity_over_time-svg.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="213" src="http://filizefe.files.wordpress.com/2009/12/600px-hard_drive_capacity_over_time-svg.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Ahora quedaba el lento traspaso de la información del disco a punto de romperse al disco nuevo. Es un proceso muy tenso, ya que en cualquier momento el disco termina por romperse y pierdes lo que no hayas copiado. Un pequeño truco que he descubierto para hacer la espera algo menos tensa es poner el disco a punto de romperse en una &lt;a href="http://en.wikipedia.org/wiki/USB_mass-storage_device_class"&gt;caja externa conectado por USB&lt;/a&gt;. De esta manera, el SO se comporta de otra forma cuando el disco deja de responder. Cuando el disco no es extraíble, el SO se queda bloqueado; pero cuando es extraíble, te pregunta por si quieres reintentar la lectura. Esto es maravilloso cuando, después de varios minutos de copia de un fichero de varios gigas, el disco duro se reinicia solo. Si no fuera por que está en modo extraíble se perdería la información. En modo extraíble esperas a que se reinicie y le dices que reintente. Continua por el mismo sector por donde lo dejó.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://the-gadgeteer.com/assets/brando-sata-ide1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="218" src="http://the-gadgeteer.com/assets/brando-sata-ide1.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;El adaptador USB para discos duros que tengo es uno barato que estaba de oferta. Tan barato era que, en medio del tenso traspaso de información, algo explotó dentro de la fuente de alimentación con el consiguiente olorcillo a electrónica tostada y el típico humillo blanco. En principio, no era problemático porque tengo la fuente del propio PC a la pude conectar el disco duro directamente. Con eso conseguí salvar el 80% de la información... hasta que el disco duro dejó de funcionar definitivamente.&lt;br /&gt;&lt;br /&gt;Como fui astuto a la hora de volcar la información, el 20% restante estaba en DVDs y, tras una breve búsqueda entre los DVDs medio olvidados, tenía recuperado todo lo que había perdido. Menos mal.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.szyhpower.com/picture/YH-3018-1.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://www.szyhpower.com/picture/YH-3018-1.JPG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;Una vez tranquilizado, me dispuse a arreglar la fuente de alimentación del adaptador USB. No sé qué tipo de &lt;a href="http://en.wikipedia.org/wiki/Fuse_(electrical)"&gt;fusible&lt;/a&gt; le habían puesto porque se había volatilizado. Con él un diodo de los gordos, de tres amperios. Con ayuda de los esquemáticos encontrados en internet pude comprobar que todos los semiconductores del primario y la mitad del secundario estaban en corto. Por un par de euros conseguí recambios equivalentes en la tienda de electrónica local. Puse más fusibles, por si las moscas, y más ajustados al valor nominal. Enchufé la fuente y empezó a funcionar de nuevo.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.rom.by/files/YH-3018.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="212" src="http://www.rom.by/files/YH-3018.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Para probar la fuente qué podría haber mejor que el disco duro recién roto. Como el fallo era mecánico, el PC debería reconocerlo aunque no pudiera acceder a la información. Bastaría con eso para comprobar que la alimentación era correcta. Sin embargo, en cuanto enchufé la alimentación, olí de nuevo a electrónica algo tostada. Muy sutilmente esta vez. Apagué con rapidez y procedí a probar el disco duro con la fuente del PC para comprobar si había pasado, definitivamente, a mejor vida electrónica.&lt;br /&gt;&lt;br /&gt;¡Y empezó a funcionar sin fallo alguno!&lt;br /&gt;&lt;br /&gt;Pero, ¿cómo puede ser? Medí los voltajes que daba la fuente de alimentación y en vez de 5V daba 8V; en vez de 12V daba 18V. ¿Cómo puede ser? ¿Un calentón eléctrico repara un fallo mecánico? Imposible. Las explicaciones que me vienen a la mente son muy rebuscadas: que los motores estuvieran algo sucios y al calentarse han disuelto algo la porquería que los bloqueaba, que se haya quemado el circuito que detecta que hay un fallo mecánico y por eso ahora es feliz, que el sobrevoltaje haya forzado la pieza mecánica y la haya vuelto a colocar en su sitio... Muy improbable todo.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://images.highspeedbackbone.net/skuimages/large/M122-7802-Main.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://images.highspeedbackbone.net/skuimages/large/M122-7802-Main.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;La cosa es que ese disco duro resucitado venía en una caja externa de Maxtor. Lo he vuelto a montar ahí y está funcionando. O parece que lo hace...&lt;br /&gt;&lt;br /&gt;No me fío y nunca me fiaré.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-1808796681891548319?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/1808796681891548319/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/10/el-extrano-caso-del-disco-duro.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/1808796681891548319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/1808796681891548319'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/10/el-extrano-caso-del-disco-duro.html' title='El extraño caso del disco duro resucitado'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-3588309125215748600</id><published>2011-10-13T18:23:00.000+02:00</published><updated>2011-10-13T18:23:33.208+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='varios'/><title type='text'>Muere un grande de la informática</title><content type='html'>Hace unos días murió &lt;a href="http://en.wikipedia.org/wiki/Dennis_Ritchie"&gt;Dennis Ritchie&lt;/a&gt;, uno de los creadores del lenguaje &lt;a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html"&gt;más usado&lt;/a&gt; en la breve historia de la informática: &lt;a href="http://en.wikipedia.org/wiki/C_(programming_language)"&gt;el lenguaje C&lt;/a&gt;. Fue un premio Turing y uno de los desarrolladores de UNIX. Como tantas veces, su muerte ha pasado desapercibida en los medios generalistas.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://upload.wikimedia.org/wikipedia/commons/0/01/Dennis_MacAlistair_Ritchie_.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://upload.wikimedia.org/wikipedia/commons/0/01/Dennis_MacAlistair_Ritchie_.jpg" width="276" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-3588309125215748600?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/3588309125215748600/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/10/muere-un-grande-de-la-informatica.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/3588309125215748600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/3588309125215748600'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/10/muere-un-grande-de-la-informatica.html' title='Muere un grande de la informática'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-6389829257179881752</id><published>2011-10-09T10:56:00.000+02:00</published><updated>2011-10-09T10:56:32.273+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='miniSL'/><title type='text'>miniSL parte 16 - El código hasta ahora</title><content type='html'>Como prometí en la última entrada de esta serie, aquí está el código que tenemos desarrollado hasta ahora. Ya llevamos 425 líneas de código. Más o menos la mitad de toda la implementación. Faltan por desarrollar el reconocimiento sintáctico, las funciones nativas y el REPL. Empezaremos en la siguiente entrada con el reconocimiento sintáctico.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: cpp"&gt;//Standard includes&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;#include &amp;lt;map&amp;gt;&lt;br /&gt;#include &amp;lt;deque&amp;gt;&lt;br /&gt;#include &amp;lt;fstream&amp;gt;&lt;br /&gt;#include &amp;lt;sstream&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;&lt;br /&gt;//Forward declarations&lt;br /&gt;class Script;&lt;br /&gt;struct CELL;&lt;br /&gt;&lt;br /&gt;//&lt;br /&gt;// Type declarations&lt;br /&gt;//&lt;br /&gt;&lt;br /&gt;typedef std::wstring STRING;&lt;br /&gt;typedef std::wistream ISTREAM;&lt;br /&gt;typedef std::wostream OSTREAM;&lt;br /&gt;typedef std::map&amp;lt;STRING, CELL*&amp;gt; STRING_MAP;&lt;br /&gt;typedef std::map&amp;lt;CELL*, CELL*&amp;gt; ENVIR_TABLE;&lt;br /&gt;typedef std::deque&amp;lt;CELL&amp;gt; CELL_STORAGE;&lt;br /&gt;typedef CELL&amp; (*NATIVE) (Script&amp; script, CELL&amp; args, CELL&amp; envir);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;//&lt;br /&gt;// CELL STRUCTURE&lt;br /&gt;//&lt;br /&gt;&lt;br /&gt;enum CELL_TYPE&lt;br /&gt;{&lt;br /&gt; UNUSED, &lt;br /&gt;&lt;br /&gt; //Literals&lt;br /&gt; EMPTY_LIT, INT_LIT, STRING_LIT,&lt;br /&gt;&lt;br /&gt; //Value constructors&lt;br /&gt; LAMBDA_VAL, NATIVE_VAL, ENVIR_VAL, BOOL_VAL, &lt;br /&gt;&lt;br /&gt; //Code constructors&lt;br /&gt; NAME_CODE, COMBINE_CODE,&lt;br /&gt;&lt;br /&gt; //Value and code constructors&lt;br /&gt; CONS_CTOR&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;struct CELL&lt;br /&gt;{&lt;br /&gt; CELL_TYPE type;&lt;br /&gt; bool mark;      //Garbage collection mark&lt;br /&gt; union&lt;br /&gt; {&lt;br /&gt;  CELL* next_unused;   //UNUSED&lt;br /&gt;  int int_val;    //INT_LIT&lt;br /&gt;  bool bool_val;    //BOOL_VAL&lt;br /&gt;  STRING const* string_val; //STRING_LIT&lt;br /&gt;  CELL* head;     //CONS.&lt;br /&gt;  CELL* code;     //LAMBDA_VAL. The cell must be a CONS_CTOR with parameters and body&lt;br /&gt;  NATIVE native;    //NATIVE_VAL&lt;br /&gt;  ENVIR_TABLE* envir_table; //ENVIR_VAL&lt;br /&gt;  CELL* op;     //COMBINE_CODE. The cell must be code (Any *_CODE type or CONS or EMPTY)&lt;br /&gt; };&lt;br /&gt;&lt;br /&gt; union&lt;br /&gt; {&lt;br /&gt;  CELL* tail;   //CONS. Must be CONS or EMPTY.&lt;br /&gt;  CELL* closure;  //LAMBDA_VAL. The cell must be an environment (ENVIR_VAL)&lt;br /&gt;  CELL* parent_envir; //ENVIR_VAL. The pointer may be NULL or an environment cell (ENVIR_VAL)&lt;br /&gt;  CELL* operands;  //COMBINE_CODE. The cell must be a list of code.&lt;br /&gt; };&lt;br /&gt;&lt;br /&gt; void Print(OSTREAM&amp; o)const;&lt;br /&gt; void PrintList(OSTREAM&amp; o, STRING const&amp; separator)const;&lt;br /&gt; static void PrintEscapedString(OSTREAM&amp; o, STRING const&amp; s);&lt;br /&gt;&lt;br /&gt; int GetInteger()const   { if(type==INT_LIT) return int_val; else throw L"Integer expected"; }&lt;br /&gt; bool GetBoolean()const   { if(type==BOOL_VAL) return bool_val; else throw L"Boolean expected"; }&lt;br /&gt; STRING const&amp; GetString()const { if(type==STRING_LIT) return *string_val; else throw L"String expected"; }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;//&lt;br /&gt;// SCRIPT CLASS&lt;br /&gt;//&lt;br /&gt;&lt;br /&gt;class Script&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt; Script() : m_FirstUnused(NULL) { m_GlobalEnvir=&amp;CreateEnvir(NULL); }&lt;br /&gt; ~Script() { GCSweep(); GCSweep(); } //Sweep twice to delete everything&lt;br /&gt;&lt;br /&gt; CELL&amp; CreateCell(CELL_TYPE ct, CELL* first=NULL, CELL* second=NULL);&lt;br /&gt; CELL&amp; CreateInteger(int val){ CELL&amp; c=CreateCell(INT_LIT); c.int_val=val; return c; }&lt;br /&gt; CELL&amp; CreateBool(bool val) { CELL&amp; c=CreateCell(BOOL_VAL); c.bool_val=val; return c; }&lt;br /&gt; CELL&amp; CreateString(STRING const&amp; val);&lt;br /&gt; CELL&amp; CreateName(STRING const&amp; val);&lt;br /&gt; CELL&amp; CreateEnvir(CELL* parent);&lt;br /&gt; CELL&amp; CreateNative(NATIVE native);&lt;br /&gt;&lt;br /&gt; ENVIR_TABLE&amp; GlobalEnvirTable()const { return *m_GlobalEnvir-&amp;gt;envir_table; }&lt;br /&gt; void DefineUsualSymbols();&lt;br /&gt;&lt;br /&gt; void DefineGlobalNative(STRING const&amp; name, NATIVE nat)&lt;br /&gt; {&lt;br /&gt;  (*m_GlobalEnvir-&amp;gt;envir_table)[&amp;CreateName(name)]=&amp;CreateNative(nat);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; CELL&amp; Evaluate(CELL&amp; c, CELL&amp; envir);&lt;br /&gt; CELL&amp; EvaluateInSequence(CELL&amp; listc, CELL&amp; envir);&lt;br /&gt; CELL&amp; Evaluate(CELL&amp; c)     { return Evaluate(c, *m_GlobalEnvir); }&lt;br /&gt;&lt;br /&gt; int GarbageCollect();&lt;br /&gt; static void GCMark(CELL* c);&lt;br /&gt;&lt;br /&gt; static CELL* FindName(CELL&amp; name, CELL&amp; envir);&lt;br /&gt; static void ChangeName(CELL&amp; name, CELL&amp; envir, CELL&amp; value);&lt;br /&gt;&lt;br /&gt; void* m_User;&lt;br /&gt;private:&lt;br /&gt; enum TOKEN_TYPE { T_NONE, T_RAW, T_LITERAL, T_SYMBOL, T_NAME };&lt;br /&gt;&lt;br /&gt; struct TOKEN&lt;br /&gt; {&lt;br /&gt;  TOKEN() : type(T_NONE) {}&lt;br /&gt;  TOKEN(TOKEN_TYPE t, CELL* d) : type(t), data(d) {}&lt;br /&gt;  TOKEN(ISTREAM::int_type r) : type(T_RAW), raw(r) {}&lt;br /&gt;&lt;br /&gt;  TOKEN_TYPE type;&lt;br /&gt;  union&lt;br /&gt;  {&lt;br /&gt;   CELL* data;&lt;br /&gt;   ISTREAM::int_type raw;&lt;br /&gt;  };&lt;br /&gt; };&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt; int GCSweep();&lt;br /&gt;&lt;br /&gt; CELL&amp; ApplyLambda(CELL&amp; code, CELL&amp; args, CELL&amp; closure, CELL&amp; envir);&lt;br /&gt;private:&lt;br /&gt; CELL* m_FirstUnused;&lt;br /&gt; CELL* m_GlobalEnvir;&lt;br /&gt; CELL_STORAGE m_Cells;&lt;br /&gt; STRING_MAP m_InternedStrings;&lt;br /&gt; TOKEN m_Ahead;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;//&lt;br /&gt;// (CELL) PRINTING&lt;br /&gt;//&lt;br /&gt;&lt;br /&gt;void CELL::Print(OSTREAM&amp; o)const&lt;br /&gt;{&lt;br /&gt; switch(type)&lt;br /&gt; {&lt;br /&gt; default:  o &amp;lt;&amp;lt; L"{{**UNKNOWN**}}"; break;&lt;br /&gt; case UNUSED: o &amp;lt;&amp;lt; L"{{**UNUSED**}}"; break;&lt;br /&gt; case INT_LIT: o &amp;lt;&amp;lt; std::dec &amp;lt;&amp;lt; int_val; break;&lt;br /&gt; case BOOL_VAL: o &amp;lt;&amp;lt; (bool_val ? L"true" : L"false"); break;&lt;br /&gt; case LAMBDA_VAL:o &amp;lt;&amp;lt; L"{{ "; code-&amp;gt;Print(o); o &amp;lt;&amp;lt; L" }}"; break;&lt;br /&gt; case NATIVE_VAL:o &amp;lt;&amp;lt; L"{{NATIVE}}"; break;&lt;br /&gt; case STRING_LIT:PrintEscapedString(o, *string_val); break;&lt;br /&gt; case NAME_CODE: o &amp;lt;&amp;lt; L"@"; PrintEscapedString(o, *string_val); break;&lt;br /&gt;&lt;br /&gt; case CONS_CTOR: case EMPTY_LIT:&lt;br /&gt;  o &amp;lt;&amp;lt; L"[";&lt;br /&gt;  PrintList(o, L", ");&lt;br /&gt;  o &amp;lt;&amp;lt; L"]";&lt;br /&gt;  break;&lt;br /&gt;&lt;br /&gt; case ENVIR_VAL: o &amp;lt;&amp;lt; L"{{ENVIR ";&lt;br /&gt;  for(ENVIR_TABLE::const_iterator i=envir_table-&amp;gt;begin(); i!=envir_table-&amp;gt;end(); ++i)&lt;br /&gt;  {&lt;br /&gt;   o &amp;lt;&amp;lt; *i-&amp;gt;first-&amp;gt;string_val &amp;lt;&amp;lt; L"= ";&lt;br /&gt;   i-&amp;gt;second-&amp;gt;Print(o);&lt;br /&gt;  }&lt;br /&gt;  o &amp;lt;&amp;lt; L"}}";&lt;br /&gt;  break;&lt;br /&gt;&lt;br /&gt; case COMBINE_CODE:&lt;br /&gt;  op-&amp;gt;Print(o);&lt;br /&gt;  o &amp;lt;&amp;lt; L"(";&lt;br /&gt;  operands-&amp;gt;PrintList(o, L", ");&lt;br /&gt;  o &amp;lt;&amp;lt; L")";&lt;br /&gt;  break;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void CELL::PrintList(OSTREAM&amp; o, STRING const&amp; separator)const&lt;br /&gt;{&lt;br /&gt; for(CELL const* c=this; c-&amp;gt;type==CONS_CTOR; c=c-&amp;gt;tail)&lt;br /&gt; {&lt;br /&gt;  if(c!=this)&lt;br /&gt;   o &amp;lt;&amp;lt; separator;&lt;br /&gt;  c-&amp;gt;head-&amp;gt;Print(o);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void CELL::PrintEscapedString(OSTREAM&amp; o, STRING const&amp; s)&lt;br /&gt;{&lt;br /&gt; o &amp;lt;&amp;lt; L"\"";&lt;br /&gt; for(STRING::const_iterator i=s.begin(); i!=s.end(); ++i)&lt;br /&gt; {&lt;br /&gt;  if(*i&amp;lt;32) o &amp;lt;&amp;lt; L"\\x" &amp;lt;&amp;lt; std::hex &amp;lt;&amp;lt; (unsigned int)(unsigned)*i &amp;lt;&amp;lt; L";";&lt;br /&gt;  else  o &amp;lt;&amp;lt; *i;&lt;br /&gt; }&lt;br /&gt; o &amp;lt;&amp;lt; L"\"";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;//&lt;br /&gt;// ALLOCATION AND GARBAGE COLLECTION&lt;br /&gt;//&lt;br /&gt;&lt;br /&gt;CELL&amp; Script::CreateCell(CELL_TYPE ct, CELL* first, CELL* second)&lt;br /&gt;{&lt;br /&gt; CELL* p;&lt;br /&gt; if(m_FirstUnused==NULL)&lt;br /&gt; {&lt;br /&gt;  CELL c;&lt;br /&gt;  m_Cells.push_back(c);&lt;br /&gt;  p=&amp;m_Cells.back();&lt;br /&gt; }&lt;br /&gt; else&lt;br /&gt; {&lt;br /&gt;  p=m_FirstUnused;&lt;br /&gt;  m_FirstUnused=p-&amp;gt;next_unused;&lt;br /&gt; }&lt;br /&gt; p-&amp;gt;mark=false;&lt;br /&gt; p-&amp;gt;type=ct;&lt;br /&gt; p-&amp;gt;head=first;&lt;br /&gt; p-&amp;gt;tail=second;&lt;br /&gt; return *p;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;CELL&amp; Script::CreateString(STRING const&amp; val)&lt;br /&gt;{&lt;br /&gt; CELL&amp; c=CreateCell(STRING_LIT);&lt;br /&gt; c.string_val=new STRING(val);&lt;br /&gt; return c;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;CELL&amp; Script::CreateName(STRING const&amp; val)&lt;br /&gt;{&lt;br /&gt; STRING_MAP::const_iterator i=m_InternedStrings.find(val);&lt;br /&gt; if(i==m_InternedStrings.end())&lt;br /&gt; {&lt;br /&gt;  CELL&amp; c=CreateCell(NAME_CODE);&lt;br /&gt;  i=m_InternedStrings.insert(std::make_pair(val, &amp;c)).first;&lt;br /&gt;  c.string_val=&amp;i-&amp;gt;first;&lt;br /&gt; }&lt;br /&gt; return *i-&amp;gt;second;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;CELL&amp; Script::CreateEnvir(CELL* parent)&lt;br /&gt;{&lt;br /&gt; CELL&amp; c=CreateCell(ENVIR_VAL);&lt;br /&gt; c.envir_table=new ENVIR_TABLE;&lt;br /&gt; c.parent_envir=parent;&lt;br /&gt; return c;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;CELL&amp; Script::CreateNative(NATIVE native)&lt;br /&gt;{&lt;br /&gt; CELL&amp; c=CreateCell(NATIVE_VAL);&lt;br /&gt; c.native=native;&lt;br /&gt; return c;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int Script::GarbageCollect()&lt;br /&gt;{&lt;br /&gt; GCMark(m_GlobalEnvir);&lt;br /&gt; return GCSweep();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void Script::GCMark(CELL* c)&lt;br /&gt;{&lt;br /&gt; if(c==NULL || c-&amp;gt;mark)&lt;br /&gt;  return;&lt;br /&gt;&lt;br /&gt; c-&amp;gt;mark=true;&lt;br /&gt;&lt;br /&gt; switch(c-&amp;gt;type)&lt;br /&gt; {&lt;br /&gt; case UNUSED:  throw L"Marking unused cell";&lt;br /&gt; case CONS_CTOR:  GCMark(c-&amp;gt;head); GCMark(c-&amp;gt;tail);  break;&lt;br /&gt; case LAMBDA_VAL: GCMark(c-&amp;gt;code); GCMark(c-&amp;gt;closure);  break;&lt;br /&gt; case COMBINE_CODE: GCMark(c-&amp;gt;op);  GCMark(c-&amp;gt;operands); break;&lt;br /&gt;&lt;br /&gt; case ENVIR_VAL:&lt;br /&gt;  GCMark(c-&amp;gt;parent_envir);&lt;br /&gt;  for(ENVIR_TABLE::const_iterator i=c-&amp;gt;envir_table-&amp;gt;begin(); i!=c-&amp;gt;envir_table-&amp;gt;end(); ++i)&lt;br /&gt;  {&lt;br /&gt;   GCMark(i-&amp;gt;first);&lt;br /&gt;   GCMark(i-&amp;gt;second);&lt;br /&gt;  }&lt;br /&gt;  break;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int Script::GCSweep()&lt;br /&gt;{&lt;br /&gt; int count=0;&lt;br /&gt; for(CELL_STORAGE::iterator i=m_Cells.begin(); i!=m_Cells.end(); ++i)&lt;br /&gt; {&lt;br /&gt;  if(i-&amp;gt;mark)&lt;br /&gt;  {&lt;br /&gt;   i-&amp;gt;mark=false;&lt;br /&gt;   continue;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  if(i-&amp;gt;type==UNUSED)&lt;br /&gt;   continue;&lt;br /&gt;&lt;br /&gt;  ++count;&lt;br /&gt;&lt;br /&gt;  switch(i-&amp;gt;type)&lt;br /&gt;  {&lt;br /&gt;  case STRING_LIT: delete i-&amp;gt;string_val;      break;&lt;br /&gt;  case ENVIR_VAL:  delete i-&amp;gt;envir_table;      break;&lt;br /&gt;  case NAME_CODE:  m_InternedStrings.erase(*i-&amp;gt;string_val); break;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  i-&amp;gt;type=UNUSED;&lt;br /&gt;  i-&amp;gt;next_unused=m_FirstUnused;&lt;br /&gt;  m_FirstUnused=&amp;*i;&lt;br /&gt; }&lt;br /&gt; return count;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//&lt;br /&gt;// EVALUATION&lt;br /&gt;//&lt;br /&gt;&lt;br /&gt;CELL&amp; Script::Evaluate(CELL&amp; c, CELL&amp; envir)&lt;br /&gt;{&lt;br /&gt; CELL* aux;&lt;br /&gt; switch(c.type)&lt;br /&gt; {&lt;br /&gt;  //Non evaluable&lt;br /&gt; case UNUSED: throw L"Evaluating an unused cell";&lt;br /&gt; default:  throw L"Evaluating an unknown cell";&lt;br /&gt; case LAMBDA_VAL:throw L"Evaluating a lambda value";&lt;br /&gt; case NATIVE_VAL:throw L"Evaluating a native";&lt;br /&gt; case ENVIR_VAL: throw L"Evaluating an environment";&lt;br /&gt;&lt;br /&gt;  //Literals&lt;br /&gt; case INT_LIT: case BOOL_VAL: case STRING_LIT: case EMPTY_LIT:&lt;br /&gt;  return c;&lt;br /&gt;&lt;br /&gt;  //Code constructors&lt;br /&gt; case CONS_CTOR:  return CreateCell(CONS_CTOR, &amp;Evaluate(*c.head, envir), &amp;Evaluate(*c.tail, envir));&lt;br /&gt;&lt;br /&gt; case NAME_CODE: &lt;br /&gt;  if((aux=FindName(c, envir))==NULL)&lt;br /&gt;   throw L"Unknown name";&lt;br /&gt;  return *aux;&lt;br /&gt;&lt;br /&gt; case COMBINE_CODE:&lt;br /&gt;  switch((aux=&amp;Evaluate(*c.op, envir))-&amp;gt;type)&lt;br /&gt;  {&lt;br /&gt;  case LAMBDA_VAL: return ApplyLambda(*aux-&amp;gt;code, *c.operands, *aux-&amp;gt;closure, envir);&lt;br /&gt;  case NATIVE_VAL: return aux-&amp;gt;native(*this, *c.operands, envir);&lt;br /&gt;  default:   throw L"Non-combinable value";&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;CELL&amp; Script::EvaluateInSequence(CELL&amp; c, CELL&amp; envir)&lt;br /&gt;{&lt;br /&gt; CELL* aux=&amp;CreateCell(EMPTY_LIT);&lt;br /&gt; for(CELL* p=&amp;c; p-&amp;gt;type==CONS_CTOR; p=p-&amp;gt;tail)&lt;br /&gt;  aux=&amp;Evaluate(*p-&amp;gt;head, envir);&lt;br /&gt; return *aux;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;CELL* Script::FindName(CELL&amp; name, CELL&amp; envir)&lt;br /&gt;{&lt;br /&gt; //Try to find the name in current environment&lt;br /&gt; ENVIR_TABLE::const_iterator i=envir.envir_table-&amp;gt;find(&amp;name);&lt;br /&gt; if(i!=envir.envir_table-&amp;gt;end())&lt;br /&gt;  return i-&amp;gt;second;&lt;br /&gt;&lt;br /&gt; //Failed, try parent&lt;br /&gt; if(envir.parent_envir!=NULL)&lt;br /&gt;  return FindName(name, *envir.parent_envir);&lt;br /&gt;&lt;br /&gt; //Failed also, not found&lt;br /&gt; return NULL;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void Script::ChangeName(CELL&amp; name, CELL&amp; envir, CELL&amp; value)&lt;br /&gt;{&lt;br /&gt; //Try to find the name in current environment&lt;br /&gt; ENVIR_TABLE::iterator i=envir.envir_table-&amp;gt;find(&amp;name);&lt;br /&gt; if(i!=envir.envir_table-&amp;gt;end())&lt;br /&gt; {&lt;br /&gt;  (*envir.envir_table)[&amp;name]=&amp;value;&lt;br /&gt;  return;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; //Failed, try parent&lt;br /&gt; if(envir.parent_envir!=NULL)&lt;br /&gt;  return ChangeName(name, *envir.parent_envir, value);&lt;br /&gt;&lt;br /&gt; //Failed also, not found&lt;br /&gt; throw L"Name to be changed is undefined";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;CELL&amp; Script::ApplyLambda(CELL&amp; code, CELL&amp; args, CELL&amp; closure, CELL&amp; envir)&lt;br /&gt;{&lt;br /&gt; CELL&amp; new_envir=CreateEnvir(&amp;closure);&lt;br /&gt; CELL* params=code.head;&lt;br /&gt; CELL* arguments=&amp;args;&lt;br /&gt; while(params-&amp;gt;type==CONS_CTOR &amp;&amp; arguments-&amp;gt;type==CONS_CTOR)&lt;br /&gt; {&lt;br /&gt;  (*new_envir.envir_table)[params-&amp;gt;head]=&amp;Evaluate(*arguments-&amp;gt;head, envir);&lt;br /&gt;  params=params-&amp;gt;tail, arguments=arguments-&amp;gt;tail;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; if((params-&amp;gt;type!=CONS_CTOR) != (arguments-&amp;gt;type!=CONS_CTOR))&lt;br /&gt;  throw L"Invalid arity";&lt;br /&gt;&lt;br /&gt; return EvaluateInSequence(*code.tail-&amp;gt;head, new_envir);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-6389829257179881752?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/6389829257179881752/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/10/minisl-parte-16-el-codigo-hasta-ahora.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6389829257179881752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6389829257179881752'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/10/minisl-parte-16-el-codigo-hasta-ahora.html' title='miniSL parte 16 - El código hasta ahora'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-890142563264118724</id><published>2011-09-29T19:40:00.000+02:00</published><updated>2011-09-29T19:40:33.912+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lenguajes de programación'/><title type='text'>Todas las funciones están en CPS</title><content type='html'>Hace algún tiempo hablé del &lt;a href="http://elmanantialdebits.blogspot.com/2011/04/transformacion-cps.html"&gt;CPS&lt;/a&gt; y las &lt;a href="http://elmanantialdebits.blogspot.com/2010/10/semantica-operacional-de-continuaciones.html"&gt;continuaciones&lt;/a&gt;. Había un detalle que hacía completamente incompatible el estilo CPS con el estilo normal de programación: toda función en CPS requiere un parámetro extra que es la continuación. Una función normal se definiría más o menos así:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;doble(x) = x+x&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;Al hacer el cambio a CPS, y suponiendo que la suma es una operación predefinida que no se pasa a CPS, obtendríamos lo siguiente:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;doble_CPS(x,k) = k(x+x)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La nueva función requiere ese argumento extra que es la continuación &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;k&lt;/span&gt;. La continuación es una función que no regresa y que representa el resto de la computación. Lo que vamos a hacer con el resultado del doble.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #666666;"&gt;Nota: El que una continuación no regrese es muy interesante desde el punto de vista de la teoría de tipos. Su tipo sería [$T\rightarrow \bot$] que es igual a [$¬ T$], pero dejaré una explicación más profunda para otra entrada más adelante.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Bien. Ahora pensemos qué pasa si tengo un lenguaje de programación en el cual la compilación va a un ensamblador genérico. Una llamada a la función doble, en ensamblador, sería algo así:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;PUSH x&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;CALL doble&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;Primero insertamos el parámetro en la pila y luego llamamos a &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;doble&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;. Si la llamada fuera la versión CPS tendríamos algo así:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;PUSH x&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;PUSH k&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;CALL doble_CPS&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;Esto impediría que un lenguaje cuyo compilador transformase el código a CPS interactuase con otro que no usase la transformación a CPS. En un caso se espera un argumento y en el otro dos.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;Sin embargo, esto no es así. Prácticamente todos los procesasores reales (incluyendo &lt;a href="http://stackoverflow.com/questions/7060970/substitutes-for-x86-assembly-call-instruction"&gt;el x86&lt;/a&gt;) son de estilo CPS y hay que decir, en cada llamada, cuál es la continuación. ¿Cómo? Observando con detenimiento la instrucción de llamada &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;CALL&lt;/span&gt;&lt;span style="font-family: inherit;"&gt; de estos procesadores. La instrucción&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;CALL f&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;es equivalente a&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;PUSH l&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;JUMP f&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;l:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;Donde l es una etiqueta, un indicador de dirección de código en &lt;a href="http://en.wikipedia.org/wiki/Assembly_language"&gt;ensamblador&lt;/a&gt; y &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;JUMP&lt;/span&gt;&lt;span style="font-family: inherit;"&gt; una &lt;a href="http://moisesrbb.tripod.com/unidad5.htm"&gt;instrucción de salto&lt;/a&gt;. Esa es la continuación. La dirección de código &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;l&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;. Eso significa que podríamos llamar a la función &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;doble&lt;/span&gt;&lt;span style="font-family: inherit;"&gt; en modo CPS de la siguiente forma.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;PUSH x&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;PUSH k&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;JUMP doble&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;Las dos últimas instrucciones son el equivalente al &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;CALL&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;, pero diciendo que queremos que regrese, no a la instrucción inmediatamente posterior al salto, sino a la que sea &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;k&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;De esta manera se pueden mezclar funciones usuales con funciones en CPS. De hecho, las funciones usuales ya están en CPS sólo que "disfrazadas" por el uso de &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;CALL&lt;/span&gt;&lt;span style="font-family: inherit;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: inherit;"&gt;&lt;span style="color: #666666;"&gt;Nota: Existe un pequeño detalle extra que es el uso exhaustivo que hace la transformación a CPS de las clausuras léxicas. Las funciones usuales guardan su entorno en la pila por lo que se destruye al salir de la función. Existen técnicas para evitar esto: los &lt;a href="http://www.lua.org/pil/27.3.3.html"&gt;upvalues&lt;/a&gt; de LUA o en &lt;a href="http://en.wikipedia.org/wiki/Escape_analysis"&gt;análisis de escape&lt;/a&gt; de la función para crear los entornos en el montículo en vez de la pila.&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-890142563264118724?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/890142563264118724/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/09/todas-las-funciones-estan-en-cps.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/890142563264118724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/890142563264118724'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/09/todas-las-funciones-estan-en-cps.html' title='Todas las funciones están en CPS'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-4355668551416042807</id><published>2011-09-26T13:18:00.000+02:00</published><updated>2011-09-26T13:18:00.301+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Máquinas virtuales'/><category scheme='http://www.blogger.com/atom/ns#' term='calculabilidad'/><category scheme='http://www.blogger.com/atom/ns#' term='semántica formal'/><title type='text'>Semántica formal para clausuras léxicas</title><content type='html'>El &lt;a href="http://www.cs.bham.ac.uk/~axj/pub/papers/lambda-calculus.pdf"&gt;lambda cálculo&lt;/a&gt; es una herramienta asombrosa. En pocas líneas puedes definir un modelo de computación. Esta simplicidad permite transmitir ideas de manera formal con relativa facilidad. Por esa razón estuve pensando cómo explicar &lt;a href="http://elmanantialdebits.blogspot.com/2011/09/que-es-una-clausura-lexica.html"&gt;la clausura léxica&lt;/a&gt; de manera matemática.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;El lambda cálculo con semántica natural&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Empezaré por el lambda cálculo con &lt;a href="http://en.wikipedia.org/wiki/Big_step_operational_semantics#Natural_semantics"&gt;semántica natural (también llamada operacional de paso grande&lt;/a&gt;). La sintaxis del lambda cálculo es muy sencilla. [$$t::=x\mid tt\mid \lambda x.t$$] Este tipo de definiciones sintácticas se leen así:&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$t::=$]&lt;/td&gt;&lt;td&gt;Un &lt;strong&gt;término&lt;/strong&gt; (o &lt;strong&gt;expresión&lt;/strong&gt;) es&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$x$]&lt;/td&gt;&lt;td&gt;o bien una &lt;strong&gt;variable&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$tt$]&lt;/td&gt;&lt;td&gt;o bien una &lt;strong&gt;aplicación&lt;/strong&gt; de un término sobre otro&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$\lambda x.t$]&lt;/td&gt;&lt;td&gt;o bien una función que toma una variable y devuelve un valor calculado por un término. Esto es a lo que se llama una &lt;strong&gt;abstracción lambda&lt;/strong&gt; o &lt;strong&gt;función anónima&lt;/strong&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #666666;"&gt;Nota: La aplicación se asocia por la izquierda. Entonces, en vez de escribir [$(((t_1 t_2) t_3) t_4)$] escribimos [$t_1 t_2 t_3 t_4$].&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Lo que es la semántica es también muy fácil de expresar: un término se convierte en un valor mediante &lt;strong&gt;una relación binaria&lt;/strong&gt; [$t\Downarrow v$]. Los valores [$v$] sólo son un tipo especial de término que se denominan &lt;a href="http://elmanantialdebits.blogspot.com/2010/06/formas-normales.html"&gt;formas normales&lt;/a&gt; (nosotros vamos a usar WNF). [$$v::= \lambda x.t \mid x v_1 \cdots v_n$$]  &amp;nbsp;Estas formas normales no se pueden reducir más con las reglas de evaluación con las que vamos a expresar la semántica. Estas reglas son las siguientes:&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Regla E-VAR[$$x\Downarrow x$$]&lt;/td&gt;&lt;td&gt;Regla E-ABS[$$\lambda x.t \Downarrow \lambda x.t $$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Regla E-APVAL[$$\frac{\begin{array}{c}t_1 \Downarrow x v_1 \cdots v_k\\t_2 \Downarrow v \end{array}}{t_1 t_2 \Downarrow x v_1 \cdots v_k v}$$] &lt;/td&gt;&amp;nbsp; &lt;td&gt; Regla E-APABS [$$\frac{\begin{array}{c}t_1 \Downarrow \lambda x.t\\t_2 \Downarrow v \\ [x\leftarrow v]t\Downarrow &amp;nbsp;v'\end{array}}{t_1 t_2 \Downarrow v'}$$] &lt;/td&gt; &amp;nbsp;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Como se comprobará, las reglas E-VAR y E-ABS no son complicadas ya que tanto las variables como las abstracciones son valores. El núcleo de todo está en las aplicaciones.&lt;br /&gt;Tanto la regla E-APVAL como la regla E-APABS tienen una forma que recuerda a las fracciones. Esta es &lt;a href="http://en.wikipedia.org/wiki/Rule_of_inference"&gt;una notación usual en lógica&lt;/a&gt; para especificar &lt;strong&gt;reglas de inferencia&lt;/strong&gt; e indica que si lo de arriba, que es el &lt;strong&gt;antecedente&lt;/strong&gt;, se cumple, entonces lo de abajo, el &lt;strong&gt;consecuente&lt;/strong&gt;, se debe cumplir.&lt;br /&gt;&lt;br /&gt;La regla E-APVAL toma dos términos aplicados el [$t_2$] al [$t_1$]. Si resulta que [$t_1$] tras evaluar tiene un valor que no es una abstracción, lo único que podemos hacer es poner el valor de [$t_2$] detrás de la forma normal, haciéndola un poco más larga. Esto tiene algo más de sentido si, por ejemplo, usamos una variable que se llame [$lista$] y evaluemos algo como [$(lista\ 1\ 7) (2+3)$]. El resultado es la propia [$lista\ 1\ 7$] con un añadido que es el valor de [$2+3$]. Es decir, que [$&amp;nbsp; (lista\ 1\ 7) (2+3) \Downarrow lista\ 1\ 7\ 5$].&lt;br /&gt;&lt;br /&gt;La regla E-APABS también toma dos términos aplicados. Esta vez tiene que ocurrir que [$t_1$] se evalúa a una función [$\lambda x.t$]. Entonces, hay que aplicar el resultado de [$t_2$] que es [$v$] a la función. La forma de hacerlo es sustituir todas las apariciones de [$x$] en [$t$] por [$v$] y calcular el valor que nos da esto. La sustitución la hemos escrito como [$[x\leftarrow v]$].&lt;br /&gt;&lt;br /&gt;Entonces, si queremos calcular el doble de 1+3, sería evaluar [$(\lambda x.x+x)(1+3)$]. Usando la regla E-APABS vemos que, efectivamente, [$t_1=&amp;nbsp; \lambda x.x+x$] y que [$t_1 \Downarrow &amp;nbsp; \lambda x.x+x $] gracias a la regla E-ABS. Entonces, [$t=x+x$]. Por otra parte, [$t_2=1+3$] y [$t_2 \Downarrow 4$]. Finalmente, la sustitución a realizar es [$[x\leftarrow &amp;nbsp;4]t = 4+4$]. La evaluación es [$4+4\Downarrow 8$] por lo que [$v'=8$] y podemos decir que ocho es el doble de cuatro: [$$(\lambda x.x+x)(1+3)\Downarrow 8$$]&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #666666;"&gt;Nota: ¿Cómo es que estamos usando sumas y números si no los hemos definido? Realmente, sí que lo están. El lambda cálculo permite codificar los números (y muchas más cosas) como funciones. Esta es la llamada &lt;a href="http://en.wikipedia.org/wiki/Church_encoding"&gt;codificación de Church&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;El lambda cálculo sin sustituciones&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;El lambda cálculo es &lt;a href="http://es.wikipedia.org/wiki/Turing_completo"&gt;Turing completo&lt;/a&gt;. Esto quiere decir que cualquier función calculable se puede calcular en él. Esto, por otra parte, no significa que sea eficiente computacionalmente. De hecho, la sustitución es una operación muy costosa: hay que recorrer todo el término en el que queremos sustituir y comparar las variables y manipular grandes trozos de expresión. Las reglas exactas son estas:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;[$$[x\leftarrow t]x=t$$]&lt;/td&gt;&lt;td&gt;[$$\frac{x\ne x'}{[x\leftarrow t]x'=x'}$$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[$$[x\leftarrow t](t_1 t_2)=(&amp;nbsp; [x\leftarrow t] t_1 ) ( &amp;nbsp; [x\leftarrow t] &amp;nbsp;t_2 )$$]&lt;/td&gt;&lt;td&gt;[$$[x\leftarrow t]\lambda x.t' =&amp;nbsp; \lambda x. t' $$]&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;La última regla está más abajo y es la más divertida porque tiene que evitar &lt;a href="http://en.wikipedia.org/wiki/Free_variables_and_bound_variables"&gt;capturar las variables&lt;/a&gt;. Para hacer esto debe explorar además del término donde se sustituye el término a sustituir. Más coste.&lt;br /&gt;[$$\frac{\begin{array}{c}x\ne x'\\x'\notin fv(t)\end{array}}{[x\leftarrow t]\lambda x'.t' =&amp;nbsp; \lambda x'. [x\leftarrow t] t' }$$] Todos los creadores de compiladores e intérpretes buscan los métodos más curiosos para evitar la sustitución. Uno de estos métodos es la evaluación por entornos, aunque hay más como las &lt;a href="http://www.ncc.up.pt/~pbv/aulas/linguagens/peytonjones92implementing.pdf"&gt;máquinas G&lt;/a&gt;, los &lt;a href="http://en.wikipedia.org/wiki/Supercombinator"&gt;supercombinadores&lt;/a&gt;, etc.&lt;br /&gt;&lt;br /&gt;Nosotros vamos a usar la &lt;strong&gt;evaluación por entornos&lt;/strong&gt; que es más simple. La idea es sencilla: no sustituimos, sólo apuntamos lo que hay que sustituir. Lo apuntamos en un entorno que es una colección de vinculaciones de ese tipo. [$$ E::= \emptyset \mid E, x=v $$] Añadimos el entorno a nuestra relación de evaluación de esta manera [$$ E \vdash t \Downarrow v$$] Se podría leer "bajo el entorno [$E$] el término [$t$] se evalúa a [$v$]".&lt;br /&gt;&lt;br /&gt;La idea es sencilla, ahora hay que establecer las reglas de evaluación. Un &lt;strong&gt;primer intento&lt;/strong&gt; podría ser éste:&lt;br /&gt;&lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Regla E-VAR[$$\frac{x=v \in E}{E\vdash x\Downarrow v}$$]&lt;/td&gt;&lt;td&gt;Regla E-ABS[$$E\vdash\lambda x.t \Downarrow \lambda x.t $$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Regla E-APVAL[$$\frac{\begin{array}{c}E \vdash t_1 \Downarrow x v_1 \cdots v_k\\ E \vdash  t_2 \Downarrow v \end{array}}{E \vdash t_1 t_2 \Downarrow x v_1 \cdots v_k v}$$] &lt;/td&gt;&amp;nbsp; &lt;td&gt; Regla E-APABS [$$\frac{\begin{array}{c} E \vdash  t_1 \Downarrow \lambda x.t\\ E \vdash  t_2 \Downarrow v \\ &amp;nbsp; E,x=v \vdash t\Downarrow &amp;nbsp;v'\end{array}}{ E \vdash  t_1 t_2 \Downarrow v'}$$] &lt;/td&gt; &amp;nbsp;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;El truco está en la nueva regla E-VAR que mira en el entorno el valor de la variable encontrada y en la regla E-APABS que introduce en el entorno la vinculación.&lt;br /&gt;&lt;br /&gt;Desafortunadamente estas reglas &lt;u&gt;no funcionan&lt;/u&gt;.&lt;br /&gt;&lt;br /&gt;El problema se observa en la siguiente evaluación [$$\emptyset \vdash (\lambda y.\lambda x.y) 3 \Downarrow v'$$] La regla a aplicar sería E-APABS que me diría que [$$ y=3 \vdash \lambda x.y \Downarrow v'$$] La regla E-ABS terminaría la evaluación incorrectamente [$$ y=3 \vdash \lambda x.y \Downarrow \lambda x.y$$] en vez de la correcta [$\lambda x.3$]. Hay que evitar que se pierda el entorno en la regla E-ABS. Al perder el entorno la expresión [$\lambda x.y$] queda abierta con la variable [$y$] libre. La solución es cerrarla con una clausura. La clausura será léxica porque hemos ido &lt;strong&gt;descendiendo por las estructuras sintácticas&lt;/strong&gt; arrastrando los entornos hasta aquí.&lt;br /&gt;&lt;br /&gt;Incluyamos entonces un nuevo término a nuestra sintaxis: las &lt;strong&gt;clausuras léxicas&lt;/strong&gt;. Que son la combinación de una abstracción lambda y un entorno. [$$ t::= x\mid tt \mid \lambda x.t \mid \lambda^E x.t $$] Ahora los valores son [$$ v::= \lambda^E x.t \mid x v_1 \cdots v_k$$] y &lt;strong&gt;las reglas de evaluación correctas&lt;/strong&gt; serían &lt;br /&gt;&lt;table style="width: 100%;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Regla E-VAR[$$\frac{x=v \in E}{E\vdash x\Downarrow v}$$]&lt;/td&gt;&lt;td&gt;Regla E-ABS[$$E\vdash\lambda x.t \Downarrow \lambda^E x.t $$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Regla E-APVAL[$$\frac{\begin{array}{c}E \vdash t_1 \Downarrow x v_1 \cdots v_k\\ E \vdash  t_2 \Downarrow v \end{array}}{E \vdash t_1 t_2 \Downarrow x v_1 \cdots v_k v}$$] &lt;/td&gt;&amp;nbsp; &lt;td&gt; Regla E-APABS [$$\frac{\begin{array}{c} E \vdash  t_1 \Downarrow \lambda^{E'} x.t\\ E \vdash  t_2 \Downarrow v \\ &amp;nbsp; E',x=v \vdash t\Downarrow &amp;nbsp;v'\end{array}}{ E \vdash  t_1 t_2 \Downarrow v'}$$] &lt;/td&gt; &amp;nbsp;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;He cambiado la regla E-ABS convirtiendo la abstracción (que es código) en la clausura léxica (que es un valor) y la regla E-APABS que ahora usa el entorno de la clausura en vez del entorno de llamada.&lt;br /&gt;&lt;br /&gt;Si evaluamos otra vez &amp;nbsp; [$$\emptyset \vdash (\lambda y.\lambda x.y) 3 \Downarrow v'$$] obtenemos que [$ v'=\lambda^{y=3}x.y$]. Lo cual me dice que hay una sustitución pendiente de [$y$] por el valor [$3$]. Esta sustitución se hará cuando se aplique la función. No se perderá.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #666666;"&gt;Nota: Hay un pequeñísimo detalle a tener en cuenta en estas nuevas reglas. Si queremos hacer una lista como hicimos antes [$lista\ 1\ (1+1)$] no podremos evaluarla. Eso es así porque la variable [$lista$] no está en el entorno y no podremos aplicar la regla E-VAR. Una solución a esto es añadir un entorno inicial donde [$lista=lista$] de manera que [$ lista=lista \vdash lista\ 1\ (1+1) \Downarrow &amp;nbsp; lista\ 1\ 2$]. Esto nos debe llevar a pensar que hay dos tipos de variables las de código (&lt;strong&gt;[$lista$]&lt;/strong&gt;[$=lista$]) y las de valor ([$lista=$]&lt;strong&gt;[$lista$]&lt;/strong&gt;). Haciendo que las variables de valor tengan también entorno ([$x^E$]) abrimos la puerta a las &lt;a href="http://elmanantialdebits.blogspot.com/2009/08/higiene-en-tu-macro.html"&gt;macros higiénicas&lt;/a&gt;.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-4355668551416042807?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/4355668551416042807/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/09/semantica-formal-para-clausuras-lexicas.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/4355668551416042807'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/4355668551416042807'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/09/semantica-formal-para-clausuras-lexicas.html' title='Semántica formal para clausuras léxicas'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-3117008987300857253</id><published>2011-09-24T12:37:00.001+02:00</published><updated>2011-09-24T12:38:20.052+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='miniSL'/><title type='text'>miniSL parte 15 - Funciones auxiliares de evaluación</title><content type='html'>En la &lt;a href="http://elmanantialdebits.blogspot.com/2011/08/minisl-parte-14-la-evaluacion.html"&gt;última entrada sobre miniSL&lt;/a&gt; estuvimos estudiando la evaluación. La evaluación es directa en casi todos los casos. Únicamente cuando tenemos que ejecutar una función definida por el usuario (&lt;a href="http://elmanantialdebits.blogspot.com/2010/11/minisl-parte-5-tipos-de-celda.html"&gt;celda de tipo LAMBDA_VAL&lt;/a&gt;) necesitamos una función auxiliar.&lt;br /&gt;&lt;br /&gt;Esta función es ApplyLambda() y lo que hace es tomar&lt;br /&gt;&lt;ul&gt;&lt;li&gt;El código del usuario que hay que ejecutar (&lt;a href="http://elmanantialdebits.blogspot.com/2010/11/minisl-parte-6-campos-de-celda.html"&gt;esto está en la celda LAMBDA_VAL&lt;/a&gt;) que contiene también el nombre de los parámetros.&amp;nbsp;&lt;/li&gt;&lt;li&gt;El código de los argumentos que se le pasa a la función (esto está en el código, en la celda COMBINE_CODE)&amp;nbsp;&lt;/li&gt;&lt;li&gt;El entorno de clausura donde queremos que se evalúe el código del usuario (también está en la celda LAMBDA_VAL)&lt;/li&gt;&lt;li&gt;El entorno donde hay que evaluar los argumentos, ya que estos se evalúan en el entorno de llamada y no en el local.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL&amp;amp; Script::ApplyLambda(CELL&amp;amp; code, CELL&amp;amp; args, CELL&amp;amp; closure, CELL&amp;amp; envir)&lt;br /&gt;{&lt;/pre&gt;&lt;br /&gt;Con estos valores, la función ApplyLambda() &lt;a href="http://elmanantialdebits.blogspot.com/2011/03/minisl-parte-10-operaciones-sobre-el.html"&gt;crea un entorno nuevo&lt;/a&gt;. El entorno local. &lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL&amp;amp; new_envir=CreateEnvir(&amp;amp;closure);&lt;/pre&gt;&lt;br /&gt;Luego, evalúa los argumentos en el entorno de llamada y los va introduciendo en este entorno local con los nombres de los parámetros que se declararon en el código. Si la función era &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f(a,b,c)&lt;/span&gt; y se llama con &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f(1+2,3+4,5+6)&lt;/span&gt;, lo que &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;ApplyLambda()&lt;/span&gt; hace es evaluar &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;1+2&lt;/span&gt;, obteniendo el valor &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;3&lt;/span&gt;, y vincular la variable a al valor &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;3&lt;/span&gt; recién obtenido. Luego hace lo mismo vinculando &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;b&lt;/span&gt; a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;7&lt;/span&gt; y &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;c&lt;/span&gt; a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;11&lt;/span&gt;. Esto se hace con este bucle.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL* params=code.head;&lt;br /&gt; CELL* arguments=&amp;amp;args;&lt;br /&gt; while(params-&amp;gt;type==CONS_CTOR &amp;amp;&amp;amp; arguments-&amp;gt;type==CONS_CTOR)&lt;br /&gt; {&lt;br /&gt;  (*new_envir.envir_table)[params-&amp;gt;head]=&amp;amp;Evaluate(*arguments-&amp;gt;head, envir);&lt;br /&gt;  params=params-&amp;gt;tail, arguments=arguments-&amp;gt;tail;&lt;br /&gt; }&lt;/pre&gt;&lt;br /&gt;Bien podría ocurrir que nos sobren argumentos o parámetros. Es decir, que la &lt;a href="http://en.wikipedia.org/wiki/Arity"&gt;aridad de la función&lt;/a&gt; no coincida con la de la llamada. Eso es un error.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;if((params-&amp;gt;type!=CONS_CTOR) != (arguments-&amp;gt;type!=CONS_CTOR))&lt;br /&gt;  throw L"Invalid arity";&lt;/pre&gt;&lt;br /&gt;Finalmente, evaluamos el código. El código es una secuencia y se debe evaluar como tal usando otra función auxiliar.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;return EvaluateInSequence(*code.tail-&amp;gt;head, new_envir);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;La función auxiliar EvaluateInSequence() es sumamente sencilla. Evalúa una lista en secuencia y retorna el valor de la última expresión evaluada.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL&amp;amp; Script::EvaluateInSequence(CELL&amp;amp; c, CELL&amp;amp; envir)&lt;br /&gt;{&lt;br /&gt; CELL* aux=&amp;amp;CreateCell(EMPTY_LIT);&lt;br /&gt; for(CELL* p=&amp;amp;c; p-&amp;gt;type==CONS_CTOR; p=p-&amp;gt;tail)&lt;br /&gt;  aux=&amp;amp;Evaluate(*p-&amp;gt;head, envir);&lt;br /&gt; return *aux;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Como se observa, lo más complicado (y lento) es ir vinculando en el entorno local los valores de los argumentos a los parámetros. De hecho, en los lenguajes de programación reales, se buscan &lt;a href="http://en.wikipedia.org/wiki/Calling_convention"&gt;convenios de llamada&lt;/a&gt; que eviten esto. Por ejemplo, introduciendo los valores de los argumentos en pila con cierto orden. De esta manera, la función llamada no tiene que buscar las variables por su nombre, que también es lento, sino por su posición en memoria que es mucho más rápido.&lt;br /&gt;&lt;br /&gt;Con esto acabamos el núcleo del lenguaje. En la siguiente entrada pondré el código escrito hasta ahora y, a partir de entonces, empezaremos con el reconocimiento sintáctico del programa.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-3117008987300857253?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/3117008987300857253/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/09/minisl-parte-15-funciones-auxiliares-de.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/3117008987300857253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/3117008987300857253'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/09/minisl-parte-15-funciones-auxiliares-de.html' title='miniSL parte 15 - Funciones auxiliares de evaluación'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-1524959001139339712</id><published>2011-09-21T22:04:00.000+02:00</published><updated>2011-09-21T22:04:45.312+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='señales'/><category scheme='http://www.blogger.com/atom/ns#' term='matemáticas'/><title type='text'>La intuición tras la transformada de Laplace</title><content type='html'>Imaginemos que queremos hacer una derivada de una señal [$x(t)$].[$$\frac{d}{dt}x(t)$$] Las derivadas son &lt;a href="http://es.wikipedia.org/wiki/Aplicaci%C3%B3n_lineal"&gt;operadores lineales&lt;/a&gt;. Eso quiere decir que si dividimos la señal en dos términos [$A_1 x_1(t)+A_2 x_2(t)$] tenemos [$$&amp;nbsp; \frac{d}{dt}x(t)= &amp;nbsp;&amp;nbsp; A_1 \frac{d}{dt}x_1(t) &amp;nbsp;+&amp;nbsp; A_2 \frac{d}{dt}x_2(t) &amp;nbsp;$$] Ya que estamos, seamos astutos. Busquémonos unos términos que se &lt;a href="http://www.dervor.com/derivadas/derivada_exponencial.html"&gt;deriven con facilidad&lt;/a&gt;. Por ejemplo, [$A e^{st}$]. Si estos fueran los términos, tendríamos [$$x(t)=A_1 e^{s_1t} + A_2 e^{s_2t}$$] y entonces&amp;nbsp; [$$&amp;nbsp; \frac{d}{dt}x(t)= &amp;nbsp;&amp;nbsp; A_1 \frac{d}{dt}x_1(t)  &amp;nbsp; +&amp;nbsp; A_2 \frac{d}{dt}x_2(t) &amp;nbsp;= A_1 s_1 e^{s_1t} + A_2 s_2 e^{s_2t} $$]Mucho más fácil.&lt;br /&gt;&lt;br /&gt;Todo esto está muy bien; pero es raro que una señal sea suma de dos exponenciales (bueno, quizás &lt;a href="http://es.wikipedia.org/wiki/Funci%C3%B3n_trigonom%C3%A9trica#Relaci.C3.B3n_con_la_exponencial_compleja"&gt;no sea tan raro&lt;/a&gt;). Una opción es hacer la suma infinita, lo cual abarca muchas más señales. Sin embargo, la opción buena, buena, buena es que sea una suma de densidades. Una integral. [$$ x(t)=\int_C{A(s)e^{st}ds}$$] El único truquillo es que la amplitud depende de la constante [$s$] que usemos en la exponencial. El &lt;a href="http://neutron.ing.ucv.ve/electronica/materias/c2515/temas1_archivos/tema4.pdf"&gt;contorno de integración&lt;/a&gt; [$C$] no nos interesa ahora. Cuando este contorno existe es que la señal puede representarse así. A veces, &lt;a href="http://cnx.org/content/m12961/latest/"&gt;no existe&lt;/a&gt;. Es decir, que tampoco abarcamos todas las señales posibles, pero sí muchísimas. Todas las de interés.&lt;br /&gt;&lt;br /&gt;¿Qué pasa cuando derivamos la señal [$x(t)$] descompuesta como una integral de exponenciales? La integral es lineal, la derivada también, la variable de derivación no está relacionada con la variable del diferencial... Todo esto nos &lt;a href="http://www.mat.ucm.es/~dazagrar/docencia/cap8.pdf"&gt;permite mover la derivada bajo el signo de la integra&lt;/a&gt;l. [$$&amp;nbsp;  \frac{d}{dt}x(t)=&amp;nbsp;  \frac{d}{dt}\int_C{A(s)e^{st}ds} =&amp;nbsp;&amp;nbsp; \int_C{ \frac{d}{dt} A(s)e^{st}ds}  &amp;nbsp;$$] Y ya tenemos lo que queríamos, la derivada de una exponencial que es ella misma por la derivada de su exponente. [$$&amp;nbsp; \frac{d}{dt}x(t)=&amp;nbsp; \int_C{A(s)\ s\ e^{st}ds}  $$] Buscando la similitud con&amp;nbsp;&amp;nbsp; [$$ x(t)=\int_C{A(s)e^{st}ds}$$] es fácil ver que la derivada lo único que hace es multiplicar [$A(s)$] por [$s$]. ¡Mucho más fácil multiplicar que hacer la derivada!&lt;br /&gt;&lt;br /&gt;Esa [$A(s)$] es casi la transformada de Laplace. Digo casi porque el contorno [$C$] introduce un factor de [$2\pi j$] que hay que compensar. Entonces, si llamo [$\mathcal{L}_{x(t)}(s)$] a la transformada de Laplace de [$x(t)$], tendré que &amp;nbsp;&amp;nbsp; [$$ x(t)=\frac{1}{2\pi j}\int_C{ \mathcal{L} _{x(t)}(s)e^{st}ds}$$] Concretamente la expresión de arriba es la transformada inversa de Laplace. La &lt;a href="http://es.wikipedia.org/wiki/Transformada_de_laplace"&gt;transformada directa&lt;/a&gt; es más sencilla. &amp;nbsp; [$$ &amp;nbsp; \mathcal{L}_{x(t)}(s)=\int_0^\infty{x(t)e^{-st}dt}$$]&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-1524959001139339712?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/1524959001139339712/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/09/la-intuicion-tras-la-transformada-de.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/1524959001139339712'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/1524959001139339712'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/09/la-intuicion-tras-la-transformada-de.html' title='La intuición tras la transformada de Laplace'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-6448904256636946500</id><published>2011-09-15T10:36:00.000+02:00</published><updated>2011-09-15T10:36:33.519+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lenguajes de programación'/><title type='text'>Incompatibilidades sintácticas</title><content type='html'>&lt;strong&gt;&lt;span style="color: red;"&gt;Los operadores prefijos e infijos no pueden ser a la vez identificadores&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Si ese fuera el caso, tendríamos la siguiente ambigüedad.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;a b c //=&amp;gt; (a) b (c) si b fuera infijo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;a b c //=&amp;gt; a (b c) si b fuera prefijo&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Una solución a esto es restringir &lt;a href="http://elmanantialdebits.blogspot.com/2011/04/infija-prefija-postfija-y-circunfija.html"&gt;o bien los operadores infijos o bien los prefijos&lt;/a&gt; para que no puedan ser identificadores.&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;Las palabras clave de las sentencias no pueden ser identificadores&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Parece una perogrullada, pero hay una razón para que sea así.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;return + a //=&amp;gt; return (+a) si es palabra clave&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;return + a //=&amp;gt; (return) + (a) si es identificador&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Una solución a esto es reservar ciertos identificadores como palabras clave. Otra solución es marcar de alguna manera los identificadores que queramos que sean introductores de sentencias.&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;La tensión entre la llamada por yuxtaposición y los operadores como identificadores&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;No pueden compartir la misma categoría sintáctica (identificadores) ya que su asociatividad es distinta.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;a b c //=&amp;gt; (a b) c &amp;nbsp;si es llamada por yuxtaposición (currificación)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;a b c //=&amp;gt; a (b c) &amp;nbsp;si b es un operador prefijo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;a b c //=&amp;gt; (a) b (c) si b es un operadores infijo&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Una solución es no tener llamada por yuxtaposición. Otra solución es restringir los operadores a símbolos.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;+ - c //=&amp;gt; + (- c) &amp;nbsp;OK. No se confunde. Si son símbolos, son prefijos.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;Un operador no puede ser infijo, prefijo y postfijo a la vez&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Si ese fuera el caso, tenemos la siguiente ambigüedad. Incluso con una categoría sintáctica distinta.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;a + + b //=&amp;gt; (a +) + b &amp;nbsp;si el primer más es tomado como postfijo&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;a + + b //=&amp;gt; a + (+ b) &amp;nbsp;si el segundo más es tomado como prefijo&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;strong&gt;Llamada por yuxtaposición y tuplas son incompatibles con la sintaxis usual de llamada&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Esto sólo es relevante si la semántica es distinta. Si la semántica es la misma, la ambigüedad &lt;a href="http://en.wikipedia.org/wiki/Confluence_(abstract_rewriting)"&gt;confluye&lt;/a&gt; en un mismo significado.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f(a,b,c) //=&amp;gt; La función f aplicada por yuxtaposición a un argumento que es la tupla (a,b,c)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f(a,b,c) //=&amp;gt; La función f aplicada a tres argumentos que son a, b y c&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Una solución a esto es usar otra sintaxis para las tuplas, por ejemplo &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;[a,b,c]&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;Tuplas y parentización&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Es una ambigüedad muy usual.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;(1) //=&amp;gt; El número uno&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;(1) //=&amp;gt; Una tupla con un elemento que es el número uno&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Algunos lenguajes como &lt;a href="http://docs.python.org/reference/expressions.html#expression-lists"&gt;Python&lt;/a&gt; solucionan esto añadiendo una coma extra en el caso de ser una tupla y no una parentización.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;(1,) //=&amp;gt; Una tupla en Python&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-6448904256636946500?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/6448904256636946500/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/09/incompatibilidades-sintacticas.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6448904256636946500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6448904256636946500'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/09/incompatibilidades-sintacticas.html' title='Incompatibilidades sintácticas'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-6923577201788859749</id><published>2011-09-09T20:54:00.002+02:00</published><updated>2011-09-24T12:43:11.717+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lenguajes de programación'/><title type='text'>¿Qué es una clausura léxica?</title><content type='html'>&lt;b&gt;&lt;span style="color: red;"&gt;Expresiones abiertas&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Antes de ver qué es una clausura léxica debemos saber qué es una clausura y antes de saber qué es una clausura debemos saber qué es lo que cierra la clausura. Lo que la clausura cierra son expresiones abiertas. Ahora bien, ¿qué es una expresión abierta? Para responder a esta pregunta necesitamos saber antes qué es una &lt;b&gt;variable ligada&lt;/b&gt; y una &lt;b&gt;variable libre&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;La forma más sencilla de explicarlo es mediante un mínimo ejemplo. Definamos dos funciones.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f= λx.x+3&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;g= &lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;λ&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;x.5x&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Aunque hemos usado la misma variable “x” en ambas funciones, cada “x” tiene un significado distinto en cada función. No hay más que aplicar las funciones.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f(4) = 4+3&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;g(7) = 5·7&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La “x” de la función “f” vale 4 y la “x” de la función “g” vale 7. Esto es así porque estas “x” son variables ligadas. La “x” de “x+3” está ligada a la “λx” de “f” y la “x” de “5x” está ligada a la “ λx” de “g”.&lt;br /&gt;&lt;br /&gt;Otro ejemplo:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;h =  λx. x+y&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En este caso la “x” de “x+y” está ligada a la “λx” de “h”. Por otra parte la “y” no está ligada, es una variable libre.&lt;br /&gt;&lt;br /&gt;En “a+b” tanto “a” como “b” son variables libres y en “c+c” la “c” es una variable libre que aparece dos veces.&lt;br /&gt;&lt;br /&gt;Se llaman expresiones cerradas a las que no tienen variables libres y se llaman expresiones abiertas a las que tienen variables libres.&lt;br /&gt;&lt;br /&gt;“5+3” es una expresión cerrada.&lt;br /&gt;“λx.2x” es una expresión cerrada.&lt;br /&gt;“λx.x+x” es una expresión cerrada.&lt;br /&gt;“λxy.2x+5y+3” es una expresión cerrada.&lt;br /&gt;“a” es una expresión abierta (la variable “a” es libre).&lt;br /&gt;“λy.y+x” es una expresión abierta (la variable “x” es libre).&lt;br /&gt;“1+z” es una expresión abierta (la variable “z” es libre).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Clausuras&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Realizar una clausura consiste en &lt;b&gt;ligar&lt;/b&gt; las variables libres dándoles algún valor. Una clausura podría ser la clausura cero en la cual todas las variables libres toman el valor cero.&lt;br /&gt;&lt;br /&gt;En esta clausura la expresión “3+x” es abierta, pero se cierra a “3+0”. Igualmente, la expresión “f= λx.x+y” que tiene de variable libre a la “y”, se cierra a “f= λx.x+0”.&lt;br /&gt;&lt;br /&gt;Pero podríamos tener otro tipo de clausura. Por ejemplo, la que se usa en matemáticas que llamaremos aquí la clausura convencional. En esta clausura las variables libres toman el valor que hayan definido por nosotros los matemáticos.&lt;br /&gt;&lt;br /&gt;La expresión “cos(3)” es abierta porque “cos” es una variable libre. Ahora bien, todo el mundo sabe que “cos” es el coseno por lo que cerramos la expresión ligando la variable “cos” con la función coseno.&lt;br /&gt;En algunos casos la clausura convencional no nos sirve. Imaginemos que nos encontramos con la expresión “K(5)”. Leyendo las bibliotecas de funciones matemáticas nos damos cuenta que podría ser la &lt;a href="http://en.wikipedia.org/wiki/Bessel_function#Modified_Bessel_functions_:_I.CE.B1.2C_K.CE.B1"&gt;función de Bessel&lt;/a&gt; o la &lt;a href="http://dlmf.nist.gov/11.2#E5"&gt;función de Sturve&lt;/a&gt; o la &lt;a href="http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros_25.html"&gt;integral elíptica de primer orden&lt;/a&gt; o &lt;a href="http://dlmf.nist.gov/not/K"&gt;varias cosas más&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;La forma de resolverlo es haciendo una clausura global. En esta clausura ligamos explícitamente las variables a su significado siempre que no se diga lo contrario. Es lo que se suele hacer cuando definimos una función. El decir “f=λx.2x” significa que “f” es la función doble y, si más adelante tenemos “f(2)”, recordamos el significado de “f” que le dimos. Este tipo de clausura global es la que se usa en lenguajes de programación como el C.&lt;br /&gt;&lt;br /&gt;Por cierto, cuando digo “f=λx.2x” no sólo estoy ligando “f” para la clausura global, también estoy ligando “x” en la expresión “2x”. Esta es la clausura local. En este punto, el lector con conocimiento de informática habrá identificado las clausuras con los entornos. Realmente la clausura es el entorno (el ligado de variables) más la expresión que se cierra.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;La clausura léxica&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;El adjetivo “léxico” significa “relativo a las palabras de un lenguaje”. Es decir, que haremos la clausura según nos digan las palabras del lenguaje.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;En los lenguajes de ordenador (y en las matemáticas) las expresiones se anidan unas dentro de otras. Así, la expresión “1+2” está dentro de la expresión “7+g(1+2)”. Esto da lugar a una estructura del propio lenguaje. La clausura léxica es la que respeta esa estructura.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define x=5      //Definimos “x”&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define g(y)=x+y //Definimos “g”. La “x” es libre aquí&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En este programa, la expresión “&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define g(y)=x+y&lt;/span&gt;” está dentro de la estructura superior “&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;{ define x=5; define g(y)=x+y }&lt;/span&gt;”. En muchos lenguajes de programación las llaves {} se usan para mostrar la estructura del programa.&lt;br /&gt;&lt;br /&gt;Cuando se define la función “g(y)”, la variable “y” está ligada, pero la “x” no. Sin embargo, siguiendo la estructura del programa, el valor de “x” está definido un poco más arriba. Esto quiere decir que la clausura léxica liga la variable “x” (dentro de la función de “g”) a la “x” que está definida fuera de esa definición, pero estructuralmente por encima de ella.&lt;br /&gt;&lt;br /&gt;Podría uno pensar que la clausura léxica es un descontrol porque liga las variables como le da la gana. No es así. En este ejemplo, la clausura léxica no liga la “y” y un compilador daría un error.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define g(y)=y+7&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define f(x)=x+y&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;No hay ligazón porque la expresión “&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define g(y)=y+7&lt;/span&gt;” no define la “y”, define la “g”. Además, la “y” de “g(y)” ya está ligada a la de “y+7”.&lt;br /&gt;&lt;br /&gt;El siguiente diagrama muestra cómo, al realizar la clausura léxica, se van buscando estructura arriba las ligazones de variables.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-J2OH2a2mSSM/TmpdZ3WaEZI/AAAAAAAAAK8/YsAQDm21qDk/s1600/DiagramaClausuraLexica.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="210" src="http://2.bp.blogspot.com/-J2OH2a2mSSM/TmpdZ3WaEZI/AAAAAAAAAK8/YsAQDm21qDk/s400/DiagramaClausuraLexica.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;La clausura léxica como valor&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Una de las claves de la clausura léxica es que se son un valor. El ejemplo típico es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define f(x)=λy.x+y;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define a=f(2); &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define b=f(5);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;print a(4); //Imprime 6&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;print b(4); //Imprime 9&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En este ejemplo la expresión “λy.x+y” es una expresión abierta y la clausura léxica de la misma nos dice que hemos de ligar la “x” a la de la “f(x)”. Sin embargo esta “x” es el argumento de una función así que el resultado de “f(2)” es la clausura léxica de la expresión “λy.x+y” ligando la “x” al “2”. Esto es un valor como la cadena “hola”, sólo que es algo más largo de describir.&lt;br /&gt;&lt;br /&gt;De la misma forma “b” se define a la clausura léxica de la expresión “λy.x+y” ligando “x” al “5”. Dado que la expresión “λy.x+y” es la función que toma un “y” y devuelve “x+y”, podemos usar esa función. Es lo que se hace en los “print”.&lt;br /&gt;&lt;br /&gt;En el primer “print” usamos la variable “a” cuyo valor era “ λy.x+y” ligando la “x” al “2”. Al aplicar “a(4)” le damos un valor a “y” así que el resultado es “x+4” ligando la “x” al “2” que a su vez es “6”. Lo que se imprime. El mismo razonamiento obtenemos para “b(4)”.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;La clausura léxica y la asignación&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Existe un pequeño detalle final y consiste en distinguir ligazón y asignación. Realmente, realmente al hacer “f(2)” en este último ejemplo no ligamos la “x” de “λy.x+y” a “2”. Lo que hacemos es ligar esa “x” a la de “f(x)” y, luego, al hacer “f(2)” asignamos la “x” de “f(x)” a “2”. El siguiente diagrama lo muestra.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-1geBhSJYncI/TmpeDJ5BGRI/AAAAAAAAALA/H9XQ7Muuutg/s1600/DiagramaClausuraLexicaYAsignacion.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="172" src="http://3.bp.blogspot.com/-1geBhSJYncI/TmpeDJ5BGRI/AAAAAAAAALA/H9XQ7Muuutg/s320/DiagramaClausuraLexicaYAsignacion.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Esta distinción es importante porque en los &lt;a href="http://elmanantialdebits.blogspot.com/2010/01/lenguajes-declarativos-y-lenguajes.html"&gt;lenguajes imperativos&lt;/a&gt; se permite reasignar. Es lo que ocurre en este código.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define x=5;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define f(y)=x+y;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;print f(3); //Imprime 8&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/span&gt; &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;x=7; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;//Reasignación de x&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; print f(3); //Imprime 10&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Cuando el &lt;a href="http://elmanantialdebits.blogspot.com/2010/01/lenguajes-declarativos-y-lenguajes.html"&gt;lenguaje es funcional&lt;/a&gt; estas distinciones no son importantes porque no se puede reasignar.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-6923577201788859749?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/6923577201788859749/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/09/que-es-una-clausura-lexica.html#comment-form' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6923577201788859749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6923577201788859749'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/09/que-es-una-clausura-lexica.html' title='¿Qué es una clausura léxica?'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-J2OH2a2mSSM/TmpdZ3WaEZI/AAAAAAAAAK8/YsAQDm21qDk/s72-c/DiagramaClausuraLexica.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-160181934677139613</id><published>2011-08-25T15:57:00.000+02:00</published><updated>2011-08-25T15:57:50.554+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='señales'/><category scheme='http://www.blogger.com/atom/ns#' term='matemáticas'/><category scheme='http://www.blogger.com/atom/ns#' term='audio y música'/><category scheme='http://www.blogger.com/atom/ns#' term='circuitos'/><title type='text'>Lo que nunca me enseñaron: Los filtros de Cauer (y parte IV)</title><content type='html'>Partes anteriores: &lt;a href="http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros.html"&gt;1&lt;/a&gt;, &lt;a href="http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros_19.html"&gt;2&lt;/a&gt; y &lt;a href="http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros_22.html"&gt;3&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;Las funciones elípticas de Jacobi&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Las &lt;a href="http://es.wikipedia.org/wiki/Funci%C3%B3n_el%C3%ADptica_de_Jacobi"&gt;funciones elípticas de Jacobi&lt;/a&gt; son una generalización de las funciones trigonométricas. Hay doce funciones elípticas de Jacobi, pero sólo vamos a usar una que se llama [$cd$]  y está relacionada con el coseno. Si bien el argumento de las funciones trigonométricas son ángulos, el argumento de las funciones elípticas de Jacobi es un valor [$u$] que no tiene una relación inmediata ni con los ángulos, ni áreas ni longitudes de arco.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-PQaXUBpSRgQ/TlY8WAwipLI/AAAAAAAAAJ8/3pl3w0-qTMs/s1600/Elipse.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="258" src="http://3.bp.blogspot.com/-PQaXUBpSRgQ/TlY8WAwipLI/AAAAAAAAAJ8/3pl3w0-qTMs/s400/Elipse.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Trigonometría en la elipse usando las funciones elípticas de Jacobi [$sd$], [$nd$] y [$cd$]. Hay más funciones elípticas de Jacobi, pero sólo nos será de utilidad la [$cd$].&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;El valor [$k^'$] se llama el &lt;b&gt;comódulo elíptico&lt;/b&gt; y se relaciona con la &lt;b&gt;excentricidad&lt;/b&gt; de la elipse [$k$], también llamada el &lt;b&gt;módulo elíptico&lt;/b&gt;, de la siguiente forma. [$$ k^2+(k^')^2=1$$] Dependiendo de la excentricidad de la elipse sobre la que trabajemos las funciones de Jacobi cambian por lo que es usual presentarlas con dos argumentos.[$$cd(u,k),\ \ \ \ sd(u,k),\ \ \ \ nd(u,k)$$] En concreto, la función [$cd(u,k)$] es muy parecida al coseno cuando se observa su inversa. [$$ arccd(u,k)=\int_u^1{\frac{dt}{\sqrt{1-t^2}\sqrt{1-k^2 t^2}}}$$] Investigaremos el recorrido que hace esta función cuando [$u$] se mueve desde [$0$] hasta infinito. Empieza en [$$ arccd(0,k)=\int_0^1{\frac{dt}{\sqrt{1-t^2} \sqrt{1-k^2 t^2}}}$$] Este valor es conocido como la &lt;b&gt;&lt;a href="http://es.wikipedia.org/wiki/Integral_el%C3%ADptica_de_primera_especie"&gt;integral elíptica completa de primera especie&lt;/a&gt;&lt;/b&gt; de módulo [$k$] y se escribe usualmente como [$K(k)$].&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-e4I3R9KfdcA/TlY9tijrw_I/AAAAAAAAAKA/MG1YSADvOMI/s1600/ArcoCd0.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="223" src="http://1.bp.blogspot.com/-e4I3R9KfdcA/TlY9tijrw_I/AAAAAAAAAKA/MG1YSADvOMI/s400/ArcoCd0.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Diagrama representando el valor real resultado de la integral completa de primera especie que es el valor del [$arccd$] de cero.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Conforme aumente [$u$] por los reales, decrecerá el [$arccd$] hasta que lleguemos a [$u=1$] donde los límites de la integral van a coincidir por lo que su valor será cero. Si hacemos el recorrido simétrico hacia los valores negativos, llegaremos a [$u=-1$] donde el valor de su [$arccd$] será [$2K(k)$].&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-i61KGl9mpDk/TlY-E4a9p6I/AAAAAAAAAKE/g3KTBq2N-hE/s1600/ArcoCd1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="173" src="http://4.bp.blogspot.com/-i61KGl9mpDk/TlY-E4a9p6I/AAAAAAAAAKE/g3KTBq2N-hE/s400/ArcoCd1.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Recorrido del valor de [$arccd$] con argumentos desde cero hasta uno (y simétrico por los negativos).&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;A partir de este punto, seguir integrando significa que la raíz [$\sqrt{1-t^2}$] va a resultar en valores imaginarios. Nuestro recorrido pasará a moverse verticalmente por la gráfica hasta que [$u=\frac{1}{k}$]. A partir de este valor, la raíz  [$\sqrt{1-k^2 t^2}$] también se hace imaginaria. El valor del [$arccd$] en [$u=\frac{1}{k}$] es fácilmente calculable mediante un cambio de variables. [$$ arccd \left(\frac{1}{k},k\right)=\int_{\frac{1}{k}}^1{\frac{dt}{\sqrt{1-t^2}\sqrt{1-k^2 t^2}}}=\int_0^1{\frac{dt}{\sqrt{t^2-1}\sqrt{1-(k^')^2 t^2}}}=jK(k^' )$$] Trazando estos segmentos verticales del recorrido obtenemos el siguiente diagrama.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-K7z7dcTYB1c/TlY-1p9icZI/AAAAAAAAAKI/AznxLSLgMhs/s1600/ArcoCd1k.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="176" src="http://3.bp.blogspot.com/-K7z7dcTYB1c/TlY-1p9icZI/AAAAAAAAAKI/AznxLSLgMhs/s400/ArcoCd1k.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Recorrido del valor de [$arccd$] con argumentos desde cero hasta [$\frac{1}{k}$] (y simétrico por los negativos)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Finalmente, continuamos a partir de [$\frac{1}{k}$]. Ahora las dos raíces tienen el radicando negativo y son por tantos imaginarias, como [$j^2=-1$] el sentido de nuestro recorrido ha de ser opuesto al que inicialmente tenía. En el límite hacia el infinito será: [$$arccd(\infty,k)\rightarrow \int_\infty^1{\frac{dt}{\sqrt{1-t^2}\sqrt{1-k^2 t^2}}}=K(k)+jK(k^' )$$] Así que terminamos el recorrido de la siguiente manera.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-PxSmeZ9ofSc/TlY_V6Kv2aI/AAAAAAAAAKM/gBL5cjMplss/s1600/ArcoCdInf.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="186" src="http://1.bp.blogspot.com/-PxSmeZ9ofSc/TlY_V6Kv2aI/AAAAAAAAAKM/gBL5cjMplss/s400/ArcoCdInf.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Recorrido completo del valor de [$arccd$] con argumentos reales.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Sabiendo que al seguir este recorrido sobre la función [$cd(u,k)$] debemos obtener la función identidad, ganamos perspectiva de cómo es la función [$cd(u,k)$].&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Secciones de cd&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Su diagrama de polos y ceros se presenta a continuación y observamos que tiene &lt;b&gt;&lt;a href="http://es.wikipedia.org/wiki/Funci%C3%B3n_el%C3%ADptica"&gt;dos periodos&lt;/a&gt;&lt;/b&gt;. El usual de [$4K(k)$] que se correspondería con el [$2\pi$] de las funciones trigonométricas y otro imaginario de [$2iK(k^' )$] que aparece por esa segunda raíz cuadrada en la integral. La zona sombreada es la que se repite periódicamente tanto horizontal como verticalmente.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-4o52W5c-tCQ/TlZA6babluI/AAAAAAAAAKQ/K2Zo6XCi_oM/s1600/PoloCerosDeCd.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="382" src="http://3.bp.blogspot.com/-4o52W5c-tCQ/TlZA6babluI/AAAAAAAAAKQ/K2Zo6XCi_oM/s400/PoloCerosDeCd.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Diagrama de polos, ceros y valores destacados de [$cd$].&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Como hicimos con la función coseno, vamos a ver cómo es la función [$cd(u,k)$] en las tres secciones del recorrido de [$arccd(u,k)$]. Recordemos que en estas rectas la función [$cd(u,k)$] es real.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-Uu9rdr6VbVY/TlZBMcUCwHI/AAAAAAAAAKU/o6cefvzw76o/s1600/CdTotal.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="358" src="http://4.bp.blogspot.com/-Uu9rdr6VbVY/TlZBMcUCwHI/AAAAAAAAAKU/o6cefvzw76o/s400/CdTotal.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Tres secciones de la función [$cd$] por las rectas que va a seguir su [$arccd$]. En estas rectas el valor de [$cd$] es real y se representa a su derecha.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Para la rama negativa tenemos que [$$ cd(u+2K(k),k)=-cd(u,k)$$] Además, existe una propiedad de simetría entre [$cd(t,k)$] y [$cd(t+jK(k^' ),k)$] que usaremos más adelante. [$$cd(u+jK^' (k),k)=\frac{1}{k\ cd(u,k)}$$] En la DLMF podemos ver en 3D la función [$cd$] con sus polos bien distinguidos.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://dlmf.nist.gov/22.3.F19.mag"&gt;http://dlmf.nist.gov/22.3.F19.mag&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;La función racional elíptica&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;El lector astuto ya habrá imaginado que lo siguiente que vamos a hacer es [$$cd(n\ arccd(u ,k),k)$$] Como hicimos con los polinomios de Chebyshev, el recorrido del [$arccd$] queda ampliado [$n$] veces. Siguiéndolo, nos haremos una idea de cómo es esta función. Como antes, sólo seguiremos los valores positivos ya que los negativos son simétricos.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-ccihLKAiAeU/TlZCxo01ghI/AAAAAAAAAKY/7GMhxyVRKks/s1600/RacionalCuadradaPlano.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="383" src="http://4.bp.blogspot.com/-ccihLKAiAeU/TlZCxo01ghI/AAAAAAAAAKY/7GMhxyVRKks/s400/RacionalCuadradaPlano.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Recorrido de [$arccd$] ampliado tres veces sobre el diagrama de polos y ceros de [$cd$].&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;El resultado es una oscilación entre +1 y -1 en el primer segmento, otra oscilación entre 1 y 1/k en el segundo segmento y otra oscilación entre 1/k e infinito (cambiando de signo en cada infinito) en el tercer segmento.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-1Go0_wZG_CA/TlZC_sURR7I/AAAAAAAAAKc/j-NPW5vKM3k/s1600/RacionalCuadradaGrafica.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="246" src="http://2.bp.blogspot.com/-1Go0_wZG_CA/TlZC_sURR7I/AAAAAAAAAKc/j-NPW5vKM3k/s400/RacionalCuadradaGrafica.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Gráfica de la función [$cd(3\ arccd(x, k), k)$] con cada uno de los tramos coloreados.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Esta función no nos sirve como función [$F^2 (\omega)$] porque tendría oscilaciones en la banda de paso.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-1eAULqOmRAQ/TlZDRi1NfyI/AAAAAAAAAKg/6QJTyHM5JPY/s1600/RacionalCuadradaF.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="218" src="http://3.bp.blogspot.com/-1eAULqOmRAQ/TlZDRi1NfyI/AAAAAAAAAKg/6QJTyHM5JPY/s400/RacionalCuadradaF.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;La función anterior al cuadrado como intento de aproximación a [$F^2(\omega)$]. La banda de transición es muy ancha y tiene oscilaciones.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Afortunadamente tenemos dos [$k$] a nuestra disposición, la del [$arccd$] que llamaremos [$k_a$] y la del [$cd$] que llamaremos [$k_c$]. Entonces, se define la &lt;strong&gt;&lt;a href="http://en.wikipedia.org/wiki/Elliptic_rational_functions"&gt;función racional elíptica&lt;/a&gt;&lt;/strong&gt; de la siguiente forma:[$$R_n (u,k_a,k_c )=cd\left(n\ \frac{K(k_c )}{K(k_a )}   arccd(u ,k_a ),k_c \right)$$] La aparición del cociente [$\frac{K(k_c )}{K(k_a )}$]  es necesaria para convertir el periodo real del [$arccd$] en el periodo real del [$cd$] que ahora son distintos al tener módulos distintos. Bueno, exactamente [$n$] veces ese periodo.&lt;br /&gt;Por otra parte, ese n no lo queremos en el periodo imaginario. Querríamos tener [$$ R_n (u,k_a,k_c )=cd\left(\frac{K(k_c^' )}{K(k_a^' )}   arccd(u ,k_a ),k_c \right)$$] ¡Y podemos tener ambas condiciones si elegimos con cuidado! [$$ n=\frac{K(k_a )K(k_c^' )}{K(k_a^' )K(k_c )} $$] De esta forma el recorrido queda multiplicado sólo en la dirección horizontal.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-TD-UabOSkkE/TlZEK5xjurI/AAAAAAAAAKk/GlrYE0DTGeM/s1600/RacionalPlano.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="203" src="http://4.bp.blogspot.com/-TD-UabOSkkE/TlZEK5xjurI/AAAAAAAAAKk/GlrYE0DTGeM/s400/RacionalPlano.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;El recorrido que tomamos en la función elíptica racional con unos parámetros adecuados para que sólo se mueva medio periodo imaginario.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;La gráfica de esta función es como sigue. En ella aparece tanto la [$k_a$] como la [$k_c$] explícitamente.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-JQrOMCByuGg/TlZEdqPb9mI/AAAAAAAAAKo/1If5NvAGFmM/s1600/RacionalGrafica.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="250" src="http://1.bp.blogspot.com/-JQrOMCByuGg/TlZEdqPb9mI/AAAAAAAAAKo/1If5NvAGFmM/s400/RacionalGrafica.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Gráfica de la función elíptica racional con módulos [$k_a$] y [$k_c$] (y la [$n$] adecuada según se comentó arriba).&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Como ocurría con los polinomios de Chebyshev, esta función es real, aunque esta vez no puede expresarse como un polinomio ya que tiene polos (los infinitos). Debe expresarse como un cociente entre polinomios, de ahí que se llame función racional elíptica.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;El filtro de Cauer&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;El &lt;strong&gt;filtro de Cauer&lt;/strong&gt; o &lt;strong&gt;filtro elíptico&lt;/strong&gt; es el que toma esa función racional elíptica como [$F(\omega)$]. La gráfica de su cuadrado es la que sigue.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-MPHzc5csTCQ/TlZGTAv1_4I/AAAAAAAAAKs/vfasRAPOT8c/s1600/RacionalF.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="231" src="http://1.bp.blogspot.com/-MPHzc5csTCQ/TlZGTAv1_4I/AAAAAAAAAKs/vfasRAPOT8c/s400/RacionalF.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;La función racional elíptica como función [$F(\omega)$] de un filtro.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Ajustando para que se cumplan los requisitos de un filtro tenemos que [$$ F^2 (\omega)=\epsilon_p^2 R_n^2 \left(\frac{\omega}{\omega_p} ,\frac{\omega_p}{\omega_s} ,\epsilon_p \epsilon_s \right)$$] Donde hemos usado [$$k_a=\frac{\omega_p}{\omega_s}$$][$$ k_c=\epsilon_p \epsilon_s$$]&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-pXf4d36llNI/TlZJIpgwdqI/AAAAAAAAAK0/l45AFJL1Ows/s1600/RacionalFAjustada.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="230" src="http://4.bp.blogspot.com/-pXf4d36llNI/TlZJIpgwdqI/AAAAAAAAAK0/l45AFJL1Ows/s400/RacionalFAjustada.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;La función racional elíptica como función&amp;nbsp;&amp;nbsp;  [$F(\omega)$] de un filtro con los parámetros ajustados a las especificaciones del filtro. &amp;nbsp;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Así que un filtro de Cauer de orden [$n$] tiene la siguiente respuesta en frecuencia al cuadrado. [$$ |H(j\omega) |^2=\frac{1}{1+\epsilon_p^2 R_n^2 \left( \frac{\omega}{\omega_p} ,\frac{\omega_p}{\omega_s} ,\epsilon_p \epsilon_s  \right)}$$] Realmente, su banda de transición es mucho más pequeña que lo trazado en las gráficas anteriores. La siguiente gráfica muestra la respuesta en frecuencia bien escalada.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-GeppVx4z1VM/TlZHFBGgNvI/AAAAAAAAAKw/EmUFomiKTl0/s1600/loc_eps_ellipt1.gif" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="211" src="http://4.bp.blogspot.com/-GeppVx4z1VM/TlZHFBGgNvI/AAAAAAAAAKw/EmUFomiKTl0/s400/loc_eps_ellipt1.gif" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Respuesta en frecuencia de un filtro de Cauer&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Además, la condición de la no oscilación en la banda base y ajuste de periodos es precisamente la cota del orden del filtro. [$$ n\ge \frac{K(\frac{\omega_p}{\omega_s}) K^' (\epsilon_p \epsilon_s )}{K^' ( \frac{\omega_p}{\omega_s} )K( \epsilon_p \epsilon_s )}$$] Donde [$K^' (k)=K(k^' )$].&lt;br /&gt;Ojo: una vez hallado [$n$] con la desigualdad, hemos de modificar algún requisito para que se cumpla la igualdad. Debemos tener la igualdad si no queremos oscilaciones en la banda de transición.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;La búsqueda de la función de transferencia&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Para obtener la función de transferencia necesitamos conocer los polos y los ceros de la misma. Ambos son sencillos de calcular. Hagamos el cambio [$\omega=-js$] y empecemos por los ceros de la función de transferencia. Ocurrirán cuando [$R_n^2$] tienda a infinito. Es decir, en los polos de [$R_n^2$]. [$$R_n^2 \left(\frac{-js_{cero}}{\omega_p} ,\frac{\omega_p}{\omega_s} ,\epsilon_p \epsilon_s \right)=\infty$$] [$$n \frac{K(\epsilon_p \epsilon_s )}{K(\frac{\omega_p}{\omega_s} )}   arccd\left(\frac{-js_{cero}}{\omega_p}   ,\frac{\omega_p}{\omega_s} \right)=arccd(\infty,\epsilon_p \epsilon_s )$$]&lt;br /&gt;El miembro de la derecha es la localización de los polos de [$cd$]. Recordemos que hay dos periodos y, por la dirección del recorrido del [$arccd$] en la zona de los ceros, nos interesa el periodo real.[$$n \frac{K(\epsilon_p \epsilon_s )}{K(\frac{\omega_p}{\omega_s})}   arccd\left(\frac{-js_{cero\ m}}{\omega_p}   ,\frac{\omega_p}{\omega_s}\right)=(2m+1)K(\epsilon_p \epsilon_s )+jK^' (\epsilon_p \epsilon_s )$$]&lt;br /&gt;Despejando llegamos a la expresión siguiente. [$$ s_{cero\ m}=j\omega_p  cd\left(\frac{2m+1}{n} K\left(\frac{\omega_p}{\omega_s}\right)+jK^' \left(\frac{\omega_p}{\omega_s}\right),\frac{\omega_p}{\omega_s} \right)$$]Por la propiedad de simetría, se simplifica aún más. [$$ s_{cero\ m}=\frac{j \omega_s}{cd\left(\frac{2m+1}{n} K(\frac{\omega_p}{\omega_s}),\frac{\omega_p}{\omega_s} \right)}$$]&lt;br /&gt;Para los ceros con los que nos quedamos en H(s), el valor de [$m$] se debe mover entre [$0$] y [$n-1$]. En algunos casos el cero aparecerá en el infinito. Eso significa que no debemos tenerlo en cuenta.&lt;br /&gt;Para los polos hay que igualar [$\epsilon_p^2 R_n^2$] a menos uno. [$$ \epsilon_p^2 R_n^2 \left(\frac{\omega_{polo}}{\omega_p} , \frac{\omega_p}{\omega_s} ,\epsilon_p \epsilon_s \right)=-1$$][$$ R_n \left( \frac{\omega_{polo}}{\omega_p} , \frac{\omega_p}{\omega_s} ,\epsilon_p \epsilon_s \right) &amp;nbsp;=\frac{j}{\epsilon_p}$$] Obtenemos una expresión similar a la que teníamos para los ceros. [$$ cd\left(n\ \frac{K(\epsilon_p \epsilon_s )}{K(\frac{\omega_p}{\omega_s})}   arccd \left(\frac{-js_{polo}}{\omega_p}   ,\frac{\omega_p}{\omega_s} \right),\epsilon_p \epsilon_s \right)=\frac{j}{\epsilon_p}$$]De nuevo elegimos el periodo real.[$$ n \frac{K(\epsilon_p \epsilon_s )}{K(\frac{\omega_p}{\omega_s})}   arccd \left(\frac{-js_{polo\ m}}{\omega_p}   ,\frac{\omega_p}{\omega_s}\right)=arccd\left(\frac{j}{\epsilon_p} ,\epsilon_p \epsilon_s \right)+2mK(\epsilon_p \epsilon_s )$$]Y despejamos[$$s_{polo\ m}=j \omega_p  cd\left(\frac{K(\frac{\omega_p}{\omega_s})}{n\ K(\epsilon_p \epsilon_s ) } \left[arccd\left(\frac{j}{\epsilon_p} ,\epsilon_p \epsilon_s \right)+2mK(\epsilon_p \epsilon_s ) \right]  ,\frac{\omega_p}{\omega_s}\right )$$]&lt;br /&gt;Así podemos construir la magnitud de la función de transferencia al cuadrado a falta de la constante multiplicativa. [$$ |H(s) |^2=A^2  \frac{\prod{(s-s_{cero\ m})}}{\prod{(s-s_{polo\ m})}}$$] La constante se halla haciendo [$s=0$] en la expresión de [$|H(s) |^2$] basada en [$R_n^2$] e igualándola con la de arriba. [$$ |H(0) |^2=A^2  \frac{\prod{(0-s_{cero\ m})}}{\prod{(0-s_{polo\ m})}}=\frac{1}{1+\epsilon_p^2 R_n^2 (0,\frac{\omega_p}{\omega_s} ,\epsilon_p \epsilon_s ) }$$] Finalmente, se toman los polos con parte real menor que cero para conseguir que pueda ser realizado en la práctica.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;Epílogo&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Si el lector compara, para un mismo conjunto de especificaciones, los órdenes que se requieren de los filtros, verá que el filtro de Cauer mejora los otros dos tipos de filtros.&lt;br /&gt;&lt;br /&gt;Debido a que el orden del filtro está relacionado con el número de componentes que se necesitan para hacer un circuito eléctrico del filtro, es inmediato llegar a la conclusión de que los filtros de Cauer son más económicos.&lt;br /&gt;&lt;br /&gt;Esa es la razón por la que Cauer conseguía un filtro con las mismas prestaciones, pero con una bobina menos.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-160181934677139613?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/160181934677139613/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros_25.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/160181934677139613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/160181934677139613'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros_25.html' title='Lo que nunca me enseñaron: Los filtros de Cauer (y parte IV)'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-PQaXUBpSRgQ/TlY8WAwipLI/AAAAAAAAAJ8/3pl3w0-qTMs/s72-c/Elipse.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-8325861881980697836</id><published>2011-08-22T00:08:00.004+02:00</published><updated>2011-08-25T16:03:05.133+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='señales'/><category scheme='http://www.blogger.com/atom/ns#' term='matemáticas'/><category scheme='http://www.blogger.com/atom/ns#' term='audio y música'/><category scheme='http://www.blogger.com/atom/ns#' term='circuitos'/><title type='text'>Lo que nunca me enseñaron: Los filtros de Cauer (parte III)</title><content type='html'>La primera parte está &lt;a href="http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros.html"&gt;aquí&lt;/a&gt; y la segunda parte &lt;a href="http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros_19.html"&gt;aquí&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Los viajes del arcocoseno&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Hasta aquí todo lo visto ha sido para entender el proceso de realización de un filtro. A partir de aquí empezamos a acercarnos a los filtros elípticos. Sin embargo, antes debemos pararnos a explorar los filtros de Chebyshev. Los filtros de Chebyshev son más simples porque usan para su expresión matemática la circunferencia en vez de la elipse. Deberían llamarse filtros circulares, pero ya se ha quedado el nombre de Chebyshev.&lt;br /&gt;&lt;br /&gt;Lo primero que necesitamos para entender los filtros de Chebyshev es la definición de arcocoseno. [$$arccos(x)=\int_x^1{\frac{dt}{\sqrt{1-t^2}}}$$] Esta integral no es más que la longitud de arco de una circunferencia unitaria desde una abscisa [$x$]. (Nota: Por supuesto, es una &lt;a href="http://en.wikipedia.org/wiki/Multivalued_function"&gt;función multivaluada&lt;/a&gt;. Tomaremos sólo la rama de la raíz principal aquí).&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-pDwiEQGZm1Y/TlF5jzdiF5I/AAAAAAAAAJM/XGs1G3L5qLU/s1600/ArcoCoseno.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="263" src="http://1.bp.blogspot.com/-pDwiEQGZm1Y/TlF5jzdiF5I/AAAAAAAAAJM/XGs1G3L5qLU/s400/ArcoCoseno.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;El arcocoseno no es más que la longitud del arco marcado.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Lo sorprendente es que esta integral, el arcocoseno, tiene sentido cuando [$x$] va más allá de [$\pm 1$]. Eso sí, hemos de usar números complejos porque el radicando que aparece en la raíz se hace negativo.&lt;br /&gt;Dibujaremos el valor que toma el arcocoseno en el &lt;a href="http://en.wikipedia.org/wiki/Argand_plane"&gt;plano de Argand&lt;/a&gt; conforme [$x$] tome valores reales. Empezaremos por el arcocoseno de cero que es [$\pi/2$].&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-E3aHjYRX85Y/TlF54riCfsI/AAAAAAAAAJQ/tpOAigmeuck/s1600/ArcoCoseno0.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="276" src="http://2.bp.blogspot.com/-E3aHjYRX85Y/TlF54riCfsI/AAAAAAAAAJQ/tpOAigmeuck/s400/ArcoCoseno0.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;El arcocoseno de cero es [$\pi/2$].&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Si vamos aumentando [$x$], llegamos hasta [$arccos(1)=0$] obteniendo únicamente números reales. Es el arcocoseno clásico. Igualmente, si disminuimos [$x$], llegamos hasta [$arccos(-1)=\pi$]. Esta simetría continuará por lo que no hablaremos más de los valores negativos de [$x$].&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-5B2OZ-WoJMY/TlF6N9fOSnI/AAAAAAAAAJU/YWpe0gXWy0A/s1600/ArcoCoseno1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="206" src="http://2.bp.blogspot.com/-5B2OZ-WoJMY/TlF6N9fOSnI/AAAAAAAAAJU/YWpe0gXWy0A/s400/ArcoCoseno1.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;El recorrido desde el arcocoseno de cero al arcocoseno de uno (y menos uno).&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;En el punto [$arccos(1)=0$] ocurre que la raíz del integrando se anula. [$$\sqrt{1-t^2 }=0$$] Si seguimos moviendo [$x$] por la recta real, el arcocoseno entrará en el eje imaginario. A partir de aquí tenemos otras dos ramas, la raíz positiva y la negativa. Elegimos la positiva y recordamos para luego que hay simetrías.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-rJcJiWqG2w8/TlF6oQSBvjI/AAAAAAAAAJY/HsZ-D1EpPh8/s1600/ArcoCosenoInf.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="173" src="http://3.bp.blogspot.com/-rJcJiWqG2w8/TlF6oQSBvjI/AAAAAAAAAJY/HsZ-D1EpPh8/s400/ArcoCosenoInf.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;El recorrido del valor del arcoseno de los números reales.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Las olas del coseno&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;En los complejos, el coseno es una función &lt;a href="http://en.wikipedia.org/wiki/Holomorphic"&gt;holomorfa&lt;/a&gt;. Una de sus particularidades es la periodicidad en el eje real. Si trazamos su diagrama de ceros (no tiene polos) y añadimos algunos puntos destacados en la línea real obtenemos lo siguiente.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-Cu709PmvEhk/TlF8BFitoKI/AAAAAAAAAJc/j88xTMycK9Y/s1600/CerosDelCoseno.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="203" src="http://4.bp.blogspot.com/-Cu709PmvEhk/TlF8BFitoKI/AAAAAAAAAJc/j88xTMycK9Y/s400/CerosDelCoseno.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Los valores destacados que toma el coseno cuando su argumento es un número complejo.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Si recorremos el plano de Argand por la línea real [$x=\sigma$], obtenemos la función coseno clásica. El lado más oscuro corresponde a los valores negativos.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-fv9ANaLAznc/TlF8UStzuCI/AAAAAAAAAJg/QbApoVlNNak/s1600/CosenoRectaReal.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="297" src="http://3.bp.blogspot.com/-fv9ANaLAznc/TlF8UStzuCI/AAAAAAAAAJg/QbApoVlNNak/s400/CosenoRectaReal.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Los valores del coseno cuando su argumento es un número real ([$\omega=0$])&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Si recorremos el coseno por la recta imaginaria obtenemos el &lt;a href="http://en.wikipedia.org/wiki/Hyperbolic_cosine"&gt;coseno hiperbólico&lt;/a&gt;. Es importante darse cuenta que por estos dos recorridos el coseno siempre proporciona un valor real.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-A6-_txb0r8c/TlF8skE3MsI/AAAAAAAAAJk/OsnBCQaxhDc/s1600/CosenoRectaImaginaria.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="291" src="http://2.bp.blogspot.com/-A6-_txb0r8c/TlF8skE3MsI/AAAAAAAAAJk/OsnBCQaxhDc/s400/CosenoRectaImaginaria.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Los valores del coseno cuando su argumento es un número imaginario ([$\sigma=0$])&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Como era de esperar, al ser el arcocoseno la función inversa del coseno, si hacemos el recorrido del arcocoseno desde 0 hasta infinito, vamos visitando los argumentos cuyo coseno se mueve desde 0 hasta infinito.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-efS1N42Wisg/TlF88QVOuAI/AAAAAAAAAJo/48jIKJf7V2Y/s1600/CosenoTotal.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="332" src="http://4.bp.blogspot.com/-efS1N42Wisg/TlF88QVOuAI/AAAAAAAAAJo/48jIKJf7V2Y/s400/CosenoTotal.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Los valores del arcocoseno recorren los argumentos del coseno cuyo resultado es el argumento del arcocoseno. Son funciones inversas una de otra.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Los polinomios de Chebyshev&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Los &lt;b&gt;polinomios de Chebyshev&lt;/b&gt; se definen así: [$$C_n (x)=cos(n\ arccos(x) )$$] Para ver cómo son, observemos el recorrido de [$n\ arccos(x)$] sobre la función coseno. Es muy sencillo porque lo único que hacemos al multiplicar por [$n$] es ampliar fotográficamente [$n$] veces el recorrido del arcocoseno. En el siguiente diagrama usamos [$n=3$].&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/--LEpgGkxgDQ/TlF-N_OWkfI/AAAAAAAAAJs/evCFuILcMm4/s1600/ChebyPlano.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="297" src="http://4.bp.blogspot.com/--LEpgGkxgDQ/TlF-N_OWkfI/AAAAAAAAAJs/evCFuILcMm4/s400/ChebyPlano.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;El polinomio de Chebyshev de orden tres se obtiene ampliando por tres el recorrido del arcocoseno (la gráfica de abajo) y, luego, realizar el coseno (las dos gráficas de arriba).&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Ampliar tres veces el recorrido no cambia mucho el valor del coseno por la recta imaginaria. Lo hace más abrupto porque nos movemos más rápidamente hacia el infinito. En donde sí que hay un cambio es en la parte real donde tenemos tres cuartos de pi en vez de uno. Esto hace que se &lt;b&gt;oscile&lt;/b&gt; en esa parte.&lt;br /&gt;&lt;br /&gt;Recordemos que en estas rectas todos los valores del coseno son reales y que hay otra parte simétrica cuando [$t\lt 0$]. Con esto en mente podemos dibujar [$C_3$].&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-8mHC34bnVEc/TlF-vIPuAVI/AAAAAAAAAJw/eU9fETWbElY/s1600/ChebyGrafica.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="257" src="http://3.bp.blogspot.com/-8mHC34bnVEc/TlF-vIPuAVI/AAAAAAAAAJw/eU9fETWbElY/s400/ChebyGrafica.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Polinomio de Chebyshev de orden tres.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Observando con cuidado el recorrido de arriba, vemos que atraviesa exactamente 3 ceros del coseno: el [$\pi/2$] y su simétrico en [$5 \pi/2$] y el [$3 \pi/2$] que es su propio simétrico. Además, no es casual que los puntos donde [$x=\pm 1$] tome el valor [$y= \pm 1$] ya que son los puntos de arcocoseno nulo.&lt;br /&gt;&lt;br /&gt;Una manera fácil de calcular los polinomios de Chebyshev es la siguiente. [$$C_{n+1} (x)=cos(n\ arccos(x)+arccos(x) )=x C_n (x)+sin(n\ arccos(x) )  sin(arccos (x) )$$][$$ C_{n-1}(x)=cos(n\ arccos(x)-arccos(x) )=x C_n (x)-sin(n\ arccos(x) )  sin(arccos(x) )$$] Sumando se llega a [$C_{n+1} (x)+C_{n-1} (x)=2 x C_n (x)$] y despejando [$C_{n+1} (x)$] se obtiene la siguiente fórmula recursiva. [$$C_{n+1} (x)=2 C_n (x) - C_{n-1} (x)$$] Usando la definición se obtiene que [$C_0 (x)=1$] y [$C_1 (x)=x$] con lo que tenemos todos los datos para calcular el polinomio de Chebyshev del orden que queramos.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;El filtro de Chebyshev&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La función [$C_n^2 (\omega)$] es una buena aproximación de [$F^2 (\omega)$]. Dibujemos su gráfica para n=3.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-W35oJBcmstc/TlF_qfLCUkI/AAAAAAAAAJ0/feh_sKLupVU/s1600/ChebyAproxF.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="291" src="http://3.bp.blogspot.com/-W35oJBcmstc/TlF_qfLCUkI/AAAAAAAAAJ0/feh_sKLupVU/s400/ChebyAproxF.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;El polinomio de Chebyshev de tercer grado al cuadrado como aproximación a [$F^2(\omega)$].&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Para que cumpla los requisitos de un filtro hay que ajustarla un poco. [$$ F^2 (\omega)=\epsilon_p^2 C_n^2 \left(\frac{\omega}{\omega_p} \right)$$]&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-DZYPg-69Gts/TlF_5GZrmlI/AAAAAAAAAJ4/YXYIi8Tqvyo/s1600/ChebyAproxFAjustada.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="262" src="http://4.bp.blogspot.com/-DZYPg-69Gts/TlF_5GZrmlI/AAAAAAAAAJ4/YXYIi8Tqvyo/s400/ChebyAproxFAjustada.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;La función [$F^2(\omega)$] de un filtro de Chebyshev.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Así que un filtro de Chebyshev es el que tiene la siguiente respuesta en frecuencia al cuadrado. [$$ |H(j\omega) |^2=\frac{1}{1+\epsilon_p^2 C_n^2 \left(\frac{\omega}{\omega_p} \right)}$$] A partir de aquí procedemos como en el &lt;a href="http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros_19.html"&gt;filtro de Butterworth&lt;/a&gt;. Calculamos [$\epsilon_s$], despejamos [$n$] para el orden; calculamos los polos de [$|H(s) |^2$] (este filtro no tiene ceros) y separamos los polos para obtener [$H(s)$].&lt;br /&gt;&lt;br /&gt;Todo esto lo dejaremos para el lector que observará, entre otras cosas, que el orden requerido es menor en un filtro de Chebyshev que en un filtro de Butterworth para los mismos requisitos.&lt;br /&gt;&lt;br /&gt;El lector curioso queda emplazado para explorar los &lt;a href="http://en.wikipedia.org/wiki/Inverse_Chebyshev_filter#Type_II_Chebyshev_filters"&gt;filtros inversos de Chebyshev&lt;/a&gt; e intentar usar la misma técnica de inversión para los filtros de Butterworth.&lt;br /&gt;&lt;br /&gt;Continúa y acaba en &lt;a href="http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros_25.html"&gt;la cuarta parte&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-8325861881980697836?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/8325861881980697836/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros_22.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/8325861881980697836'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/8325861881980697836'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros_22.html' title='Lo que nunca me enseñaron: Los filtros de Cauer (parte III)'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-pDwiEQGZm1Y/TlF5jzdiF5I/AAAAAAAAAJM/XGs1G3L5qLU/s72-c/ArcoCoseno.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-3422065809011555568</id><published>2011-08-19T17:49:00.001+02:00</published><updated>2011-08-22T00:09:12.990+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='señales'/><category scheme='http://www.blogger.com/atom/ns#' term='matemáticas'/><category scheme='http://www.blogger.com/atom/ns#' term='audio y música'/><category scheme='http://www.blogger.com/atom/ns#' term='circuitos'/><title type='text'>Lo que nunca me enseñaron: Los filtros de Cauer (parte II)</title><content type='html'>&lt;a href="http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros.html"&gt;Parte 1 aquí&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;El filtro de Butterworth&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Aproximar la función [$F^2 (\omega)$] que debería valer 0 si [$\omega &amp;lt; \omega_p$] e infinito si [$\omega &amp;gt; \omega_s$] es muy sencillo. Todas las funciones monótonas (siempre crecientes) lo aproximan con más o menos éxito.&lt;br /&gt;&lt;br /&gt;Una [$F^2 (\omega)$] muy usada es [$$F^2 (\omega)=&amp;nbsp; \epsilon &amp;nbsp;_p^2 \left(\frac{ \omega }{&amp;nbsp; \omega_p } \right)^{2n}$$] Este es el llamado filtro de Butterwoth. El número [$n$] es el &lt;b&gt;orden del filtro&lt;/b&gt;. Debido a que debemos trabajar con polinomios, las potencias han de ser números naturales y, por tanto, el orden del filtro n debe ser un número natural. El orden del filtro está relacionado con el número de componentes eléctricos que va a tener nuestro circuito.&lt;br /&gt;&lt;br /&gt;Construyamos su respuesta en frecuencia al cuadrado. [$$ |H(j\omega)|^2=\frac{1}{1+\epsilon_p^2 \left(\omega/\omega_p \right)^{2n}}$$] El filtrado de frecuencias que hace este filtro se muestra a continuación. Esta gráfica es la &lt;a href="http://www.gonascent.com/papers/butter.pdf"&gt;original del artículo de Butterworth de 1930&lt;/a&gt; y representa [$|H(j\omega)|$] con [$\omega_p=1$].&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-QErnrHjDWqU/Tk52Xm2DyxI/AAAAAAAAAI4/ZU2PVBGZMp4/s1600/Buttergr.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="350" src="http://4.bp.blogspot.com/-QErnrHjDWqU/Tk52Xm2DyxI/AAAAAAAAAI4/ZU2PVBGZMp4/s400/Buttergr.jpg" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Respuesta en frecuencia de un filtro de Butterworth tal cual aparecía en su artículo de 1930.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;El valor [$\epsilon_p$] está explícitamente escrito en la ecuación, pero no sabemos nada de [$\epsilon_s$]. Hemos de usar la expresión de [$|H(j\omega) |^2$] para deducir qué valor tendremos para [$\epsilon_s$]. Bastará calcular la respuesta en frecuencia a la frecuencia [$\omega_s$]. [$$|H(j\omega_s ) |^2=\frac{1}{1+\epsilon_p^2 \left(\omega_s/\omega_p\right)^{2n}} = \frac{\epsilon_s^2}{1+\epsilon_s^2}$$][$$ \frac{1}{\epsilon_s^2}=\epsilon_p^2 \left(\frac{\omega_s}{\omega_p}\right)^{2n},\ \ \ \ \epsilon_s \epsilon_p=\left( \frac{\omega_p}{\omega_s}\right) ^n$$] Esta última expresión, muy simple gracias a la introducción de los épsilon en la parte anterior, relaciona el orden del filtro con los requisitos. Como el orden del filtro ha de ser un natural, es usual escribir la ecuación como una cota. [$$ n \ge \frac{log(\epsilon_s \epsilon_p)}{log \left( \frac{\omega_p}{\omega_s} \right) } $$]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Polos y ceros&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;La función [$|H(j\omega) |^2$] está relacionada con la respuesta en frecuencia del filtro [$|H(j\omega) |$] sin cuadrado, pero lo que nos interesa para poder implementar el filtro es la función de transferencia [$H(s)$] que abarca todos los complejos. Los pasos son los siguientes.&lt;br /&gt;&lt;br /&gt;Primero, con un cambio de variables [$\omega=-js$], convertimos [$|H(j\omega) |^2$] en [$|H(s) |^2$].&amp;nbsp; [$$ |H(s)|^2=\frac{1}{1+\epsilon_p^2 \left(-js/\omega_p \right)^{2n}}$$]&lt;br /&gt;A continuación, obtendremos la función  [$|H(s) |^2$] como un cociente de dos polinomios. Escribiremos los polinomios factorizando sus raíces. [$$|H(s) |^2=A^2  \frac{\prod{s-s_{cero m} }}{\prod{s-s_{polo m} }}$$] Las raíces del numerador se llaman &lt;b&gt;ceros&lt;/b&gt; porque cuando [$s$] sea un [$s_{cero}$], tendremos que [$|H(s) |^2=0$]. Las raíces del denominador se llaman &lt;b&gt;polos&lt;/b&gt; porque cuando [$s$] tienda a un [$s_{polo}$], todo [$|H(s) |^2$] tiende a infinito. El por qué se llaman polos es obvio cuando se hace la gráfica en tres dimensiones.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-XUrCN8m3MfM/Tk55Wqui0tI/AAAAAAAAAI8/85POulfa6SM/s1600/zeropole.gif" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="297" src="http://2.bp.blogspot.com/-XUrCN8m3MfM/Tk55Wqui0tI/AAAAAAAAAI8/85POulfa6SM/s400/zeropole.gif" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Visión 3D de la función de transferencia de un filtro de Butterworth. Se observan los polos y la respuesta en frecuencia cuya parte positiva está remarcada en rojo.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Los filtros de Butterworth no tienen ceros. Esto ocurre porque el numerador de [$|H(s) |^2$] es uno. Pero sí tienen polos cuando el denominador se anula. Es decir, cuando [$F^2 (\omega)=-1$].[$$F^2 (-js_{polo} )=-1$$][$$\epsilon_p^2 \left(\frac{-js_{polo}}{\omega_p}\right)^{2n}=-1$$][$$\epsilon_p \left(\frac{-js_{polo}}{\omega_p}\right)^n=j$$][$$&amp;nbsp; \sqrt[n]{\epsilon_p}\frac{-js_{polo}}{\omega_p}=\sqrt[n]{j}$$][$$s_{polo}=\frac{j \omega_p}{\sqrt[n]{\epsilon_p}} \sqrt[n]{j}$$]&lt;br /&gt;Usando las &lt;a href="http://es.wikipedia.org/wiki/Ra%C3%ADz_de_la_unidad"&gt;raíces de la unidad&lt;/a&gt;, llegamos a que los polos de [$|H(s) |^2$] yacen en un círculo. Como hay más de uno, los numeramos con un subíndice [$m$]. [$$s_{polo\ m}=\omega_p \epsilon_p^{\frac{-1}{n}}  e^{j\left[\frac{p}{2}+\frac{p}{2n}+\frac{2p}{n} m\right]}$$] Es interesante localizar los polos en el plano de Argand (plano complejo). El siguiente diagrama muestra los polos de [$|H(s) |^2$] de un filtro de Butterworth de orden tres.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-GOplmgrciQQ/Tk6BOrXxa6I/AAAAAAAAAJE/tRIptgiJwag/s1600/PolosButt.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="222" src="http://2.bp.blogspot.com/-GOplmgrciQQ/Tk6BOrXxa6I/AAAAAAAAAJE/tRIptgiJwag/s400/PolosButt.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Distribución de los polos de la función de transferencia al cuadrado de un filtro de Butterworth de orden tres.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Obteniendo la función de transferencia&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;La simetría que aparece en el diagrama anterior es usual en [$|H(s) |^2$] y se llama &lt;b&gt;simetría cuadrantal&lt;/b&gt;. Ocurre que [$$|H(s) |^2=|H(-s) |^2=|H(s^* ) |^2$$] por lo que la función [$|H(s) |^2$] queda completamente definida por lo que pase en sólo uno de sus cuadrantes. Esta simetría se usa para obtener [$H(s)$] a partir de [$|H(s) |^2$] mediante la siguiente ecuación: [$$|H(s) |^2=H(s)H(-s)$$] Recordemos que [$|H(s) |^2$] estaba descrita como un producto de polos y ceros. Entonces, podemos separar los polos que van para [$H(s)$] y los que van para [$H(-s)$].[$$ A^2 \frac{\prod{(s-s_{cero\ m})}}{\prod{(s-s_{polo\ m})}}=\left[A \frac{\prod{(s-s_{cero\ de\ H(s)\  m})}}{\prod{(s-s_{polo\ de\ H(s)\ m} )}}\right]\left[A \frac{\prod{(s-s_{cero\ de\ H(-s)\ m} )} }{\prod{(s-s_{polo\ de\ H(-s)\ m}) } }\right]$$] Lo que sí que hay que decidir es qué polos van para [$H(s)$] y qué polos van para [$H(-s)$]. Es fácil. Para que [$H(s)$] sea realizable físicamente y estable, hay que escoger los polos cuya parte real sea negativa. Y para que el filtro sea de fase mínima (menor dispersión) también cogeremos los ceros que tengan su parte real negativa.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-DOCw4hLfpjg/Tk6DQIU636I/AAAAAAAAAJI/C83UMVqwTgc/s1600/PolosButtEstables.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="211" src="http://4.bp.blogspot.com/-DOCw4hLfpjg/Tk6DQIU636I/AAAAAAAAAJI/C83UMVqwTgc/s400/PolosButtEstables.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Separación de los polos de [$|H(s)|^2$] que van para [$H(s)$] de los que van para [$H(-s)$].&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Una vez tenemos [$H(s)$] podemos usar alguna de las técnicas de síntesis de circuitos para realizar el filtro.&lt;br /&gt;&lt;br /&gt;Continúa en &lt;a href="http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros_22.html"&gt;la parte tres&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-3422065809011555568?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/3422065809011555568/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros_19.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/3422065809011555568'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/3422065809011555568'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros_19.html' title='Lo que nunca me enseñaron: Los filtros de Cauer (parte II)'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-QErnrHjDWqU/Tk52Xm2DyxI/AAAAAAAAAI4/ZU2PVBGZMp4/s72-c/Buttergr.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-4567008944116725000</id><published>2011-08-17T01:33:00.001+02:00</published><updated>2011-08-22T00:08:48.120+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='señales'/><category scheme='http://www.blogger.com/atom/ns#' term='matemáticas'/><category scheme='http://www.blogger.com/atom/ns#' term='audio y música'/><category scheme='http://www.blogger.com/atom/ns#' term='circuitos'/><title type='text'>Lo que nunca me enseñaron: Los filtros de Cauer (parte I)</title><content type='html'>&lt;b&gt;&lt;span style="color: red;"&gt;Introducción&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Según cuenta Van Valkenburg (ver "Analog Filter Design" 1982, página 379), sobre 1935 los ingenieros de &lt;a href="http://en.wikipedia.org/wiki/Bell_Labs"&gt;Bell Laboratories&lt;/a&gt; se llevaron una desagradable sorpresa. Su competencia alemana había sacado un teléfono al mercado que igualaba la calidad de sonido del suyo, pero usaba un inductor menos en los filtros.&lt;br /&gt;En 1935 los inductores no eran lo que hoy. Un inductor pesaba su cuarto de kilo y costaba bastante. El que los alemanes hubieran conseguido eliminarlo sin deteriorar las características del dispositivo podría llevar la empresa americana a la ruina y no era época para tonterías con los alemanes.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://www.classicrotaryphones.com/forum/index.php?PHPSESSID=d61675529c699c271189ebe2f931c644&amp;amp;action=dlattach;topic=4510.0;attach=23747;image" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://www.classicrotaryphones.com/forum/index.php?PHPSESSID=d61675529c699c271189ebe2f931c644&amp;amp;action=dlattach;topic=4510.0;attach=23747;image" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Teléfono de 1930&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Pero esa ruina no ocurrió. El inventor del método de diseño que hacía capaz ese ahorro, &lt;a href="http://en.wikipedia.org/wiki/Wilhelm_Cauer"&gt;Wilhelm Cauer&lt;/a&gt;, estaba necesitado de dinero (supongo) y quiso vender sus patentes. Para eso dio unas conferencias y los muy avispados matemáticos de Bell Laboratories tomaron nota. Una familia de funciones matemáticas se mencionó varias veces: las &lt;a href="http://mathworld.wolfram.com/JacobiEllipticFunctions.html"&gt;funciones elípticas de Jacobi&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Cuenta la leyenda que durante las dos semanas siguientes el departamento entero de matemáticas de Bell Laboratories se encerró en la biblioteca pública de Nueva York, estudiando tales funciones. Si mal no recuerda Darlington, que &lt;a href="http://www2.ee.ufpe.br/codec/historia%20RLC.pdf.pdf"&gt;lo sufrió en sus propias carnes&lt;/a&gt;, allí encontró el artículo original de &lt;a href="http://es.wikipedia.org/wiki/Carl_Gustav_Jakob_Jacobi"&gt;Jacobi&lt;/a&gt; de 1829 escrito en latín. En él estaba todo: tablas, transformaciones, aproximaciones… ¡todo!&lt;br /&gt;&lt;br /&gt;A fin de cuentas, Cauer fue estudiante de &lt;a href="http://en.wikipedia.org/wiki/Hilbert"&gt;Hilbert&lt;/a&gt; en Göttingen. Dada la prominencia del maestro, seguramente había visto de sobra estas funciones elípticas y, simplemente, les había encontrado otra aplicación. Por ese motivo, a este tipo de filtros se los denomina filtros elípticos o filtros de Cauer.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-H9PQrhXO0EI/Tkr0on63SpI/AAAAAAAAAIk/PTe1e6r_kGw/s1600/HilbertCauer.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="210" src="http://4.bp.blogspot.com/-H9PQrhXO0EI/Tkr0on63SpI/AAAAAAAAAIk/PTe1e6r_kGw/s320/HilbertCauer.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;David Hilbert y Wilhelm Cauer&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Los filtros&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Un &lt;a href="http://en.wikipedia.org/wiki/Electric_filter"&gt;filtro eléctrico&lt;/a&gt; no es más que un dispositivo que toma una señal eléctrica como la del teléfono y elimina algunas frecuencias. De esta manera podemos oír la voz sin los ruidos raros del ADSL introduciendo un filtro que elimine las frecuencias que usa el ADSL. Lógicamente, podremos usar otro filtro para quedarnos con el ADSL y quitar la voz. Así que, por un mismo cable y gracias a un par de filtros, tengo voz y datos.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-HrYU3uhw4nA/Tkr1ELURHFI/AAAAAAAAAIo/0l4wO1FJlpE/s1600/adsl-splitter-microfiltro.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-HrYU3uhw4nA/Tkr1ELURHFI/AAAAAAAAAIo/0l4wO1FJlpE/s320/adsl-splitter-microfiltro.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Splitter de ADSL que no es más que un filtro para que no se oiga el ruido de los datos de ADSL en el audio del teléfono.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Esta no es más que una de las aplicaciones de los filtros. Hay muchísimas más: &lt;a href="http://es.wikipedia.org/wiki/Multiplexaci%C3%B3n_por_divisi%C3%B3n_de_frecuencia"&gt;multiplexar&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Anti-aliasing_filter"&gt;eliminar el aliasing&lt;/a&gt;, hacer efectos de sonido y &lt;a href="http://es.wikipedia.org/wiki/Ecualizador"&gt;ecualizar&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/All-pass_filter"&gt;compensar desfases&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Modulation"&gt;modular, demodular&lt;/a&gt;… y un sinfín más que no vamos a enumerar aquí porque lo que nos interesa es el trasfondo teórico de los filtros.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;La función de transferencia y la respuesta en frecuencia&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;La forma que tienen los filtros de procesar las señales es mediante &lt;a href="http://es.wikipedia.org/wiki/Funci%C3%B3n_de_transferencia"&gt;una función de transferencia&lt;/a&gt; [$H(s)$]. Esta función está definida en los números complejos y, para que pueda ser construida físicamente, ha de ser racional (P y Q son polinomios). [$$H(s)=\frac{P(s)}{Q(s)}$$] La magnitud de la función de transferencia en el eje imaginario es la &lt;a href="http://es.wikipedia.org/wiki/Respuesta_en_frecuencia"&gt;respuesta en frecuencia&lt;/a&gt;. Esta respuesta es lo que nuestro filtro multiplicará a la amplitud cada frecuencia. Si su valor a una frecuencia es mayor que uno, esa frecuencia se amplifica. Si es menor que uno, se atenúa. Escribiremos esta magnitud así:[$$|H(j\omega)|$$] Donde [$\omega$] no es más que [$2\pi$] veces la frecuencia ([$\omega=2\pi f$]) para no tener que escribir [$2\pi$] cada vez que vayamos a usar un seno, coseno o exponencial compleja. La [$j$] es la constante imaginaria que, en ingeniería, se usa para no confundirla con la intensidad de corriente [$i$].&lt;br /&gt;&lt;br /&gt;Es importante señalar aquí que para realizar el filtro necesitamos la función [$H(s)$] con [$s$] en todo el plano complejo, pero la respuesta en frecuencia que deseamos es sólo esa función en la recta imaginaria [$|H(j\omega)|\ \ $]. Gran parte del problema estriba en pasar de [$|H(j\omega)|\ \ $], lo que queremos, a [$H(s)$], cómo hacerlo.&lt;br /&gt;&lt;br /&gt;Pero primero veamos qué queremos.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;El filtro ideal y los filtros reales&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Nos interesaría que la respuesta en frecuencia fuera ideal: todo lo que haya por encima de una frecuencia de corte [$\omega_c$] se elimina (se multiplica por 0 en la &lt;b&gt;banda de rechazo&lt;/b&gt;) y todo lo que haya por debajo se preserva (se multiplica por 1 en la &lt;b&gt;banda de paso&lt;/b&gt;). Eso significa que el [$|H(j\omega)|$] ideal tendría esta forma:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-FbHLx55s1UA/Tkr34C3328I/AAAAAAAAAIs/wj514AAphNs/s1600/FiltroIdeal.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="182" src="http://2.bp.blogspot.com/-FbHLx55s1UA/Tkr34C3328I/AAAAAAAAAIs/wj514AAphNs/s320/FiltroIdeal.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Un filtro ideal que elimina las frecuencias de la banda de rechazo y deja intactas las frecuencias de la banda de paso.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Sin embargo, esto no es posible porque las únicas funciones de transferencia que podemos realizar eléctricamente son funciones racionales (&lt;a href="http://en.wikipedia.org/wiki/Rational_function#Complex_rational_functions"&gt;recordemos: cocientes de dos polinomios&lt;/a&gt;) y son funciones continuas excepto en &lt;a href="http://es.wikipedia.org/wiki/As%C3%ADntota"&gt;asíntotas verticales&lt;/a&gt;. No es posible hacer el escalón discontinuo que vemos en la gráfica de arriba. Hay que transigir y permitir no tener exactamente un 1 o un 0 (a esto se le denomina &lt;b&gt;&lt;a href="http://es.wikipedia.org/wiki/Rizado"&gt;rizado&lt;/a&gt;&lt;/b&gt;) y dejar una banda de transición entre las bandas de paso y de rechazo.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-aCLlJIcpJ7Y/Tkr4RaL3AMI/AAAAAAAAAIw/r7q43SSf130/s1600/EspecificacionesH.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="129" src="http://2.bp.blogspot.com/-aCLlJIcpJ7Y/Tkr4RaL3AMI/AAAAAAAAAIw/r7q43SSf130/s320/EspecificacionesH.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Forma de un filtro real donde se han especificado los requisitos del mismo: frecuencia de paso [$\omega_p$], frecuencia de rechazo [$\omega_s$], rizado de paso [$r_p$] y rizado de rechazo [$r_s$].&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Ya no tenemos una frecuencia de corte, sino una frecuencia de paso [$\omega_p$] por debajo de la cual las frecuencias no se van a tocar mucho (entre [$1$] y [$r_p$]) y una frecuencia de rechazo [$\omega_s$] por encima de la cual no van a sobrevivir muchas frecuencias (como mucho se multiplica por [$r_s$] que será todo lo cercano a cero posible).&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #666666;"&gt;&lt;span style="font-size: x-small;"&gt;&lt;b&gt;Nota&lt;/b&gt;: El subíndice s viene del inglés &lt;i&gt;stopband&lt;/i&gt;.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Complicando para simplificar&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Como vemos, todo el rango de trabajo está entre el [$0$] y el [$1$]. Si elevamos al cuadrado, seguimos estando entre [$0$] y [$1$]. Esto permite trabajar con la magnitud al cuadrado que es más sencilla de calcular y siempre es real positiva. [$$ |H(j\omega)|^2=H(j\omega) H^*(j\omega)=H(j \omega )H(-j \omega )$$] El asterisco indica &lt;a href="http://es.wikipedia.org/wiki/N%C3%BAmero_complejo#Conjugado_de_un_n.C3.BAmero_complejo"&gt;complejo conjugado&lt;/a&gt;. La última igualdad saca provecho a que [$H(s)$] es racional con coeficientes reales y, por tanto, su parte imaginaria ha de ser &lt;a href="http://es.wikipedia.org/wiki/Funci%C3%B3n_herm%C3%ADtica"&gt;hermítica&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Trabajar entre [$0$] e infinito es también más sencillo. ¿Por qué? Si el límite es el [$1$], nos podemos pasar de [$1$] y eso sería erróneo. Nos tendríamos que dedicar a comprobar que nuestros cálculos nunca superasen el uno y los complicaría. En cambio, si el límite es infinito, ¡no hay límite! Los cálculos no tienen necesidad de asegurar que haya un límite y se simplifican.&lt;br /&gt;&lt;br /&gt;Forzaremos que la función [$|H(j\omega)|^2$] tenga esta forma: [$$ |H(j\omega)|^2=\frac{1}{1+F^2 ( \omega )}$$]Ahora, la función [$F^2 ( \omega )$] no tiene límite superior. A cambio, hemos de recalcular los rizados.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-1uFhUrM71A8/Tkr5wllAeHI/AAAAAAAAAI0/RzdCyjhpqoA/s1600/EspecificacionesF.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="133" src="http://4.bp.blogspot.com/-1uFhUrM71A8/Tkr5wllAeHI/AAAAAAAAAI0/RzdCyjhpqoA/s320/EspecificacionesF.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;La misma respuesta en frecuencia de antes, pero con la transformación mencionada para trabajar entre [$0$] e infinito. Hay que hacer notar cómo se han modificado los parámetros que especificaban los rizados.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Estos nuevos parámetros [$\epsilon_s$] y [$\epsilon_p$] se relacionan con los rizados originales así: [$$r_p=\sqrt{\frac{1}{1+\epsilon_p^2}},\ \ \ \ r_s=\sqrt{\frac{\epsilon_s^2}{1+ \epsilon _s^2}}$$] Llamaremos a [$\omega_p,\epsilon_p,\omega_s$] y [$\epsilon_s$] los &lt;b&gt;requisitos del filtro&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Hay que destacar que la función [$F^2 (\omega)$] sigue siendo una función racional y deberá ser el cociente de dos polinomios.&lt;br /&gt;&lt;br /&gt;Continúa &lt;a href="http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros_19.html"&gt;en parte dos&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-4567008944116725000?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/4567008944116725000/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/4567008944116725000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/4567008944116725000'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/08/lo-que-nunca-me-ensenaron-los-filtros.html' title='Lo que nunca me enseñaron: Los filtros de Cauer (parte I)'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-H9PQrhXO0EI/Tkr0on63SpI/AAAAAAAAAIk/PTe1e6r_kGw/s72-c/HilbertCauer.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-6558636770448980580</id><published>2011-08-01T20:32:00.000+02:00</published><updated>2011-08-01T20:32:40.279+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='miniSL'/><title type='text'>miniSL parte 14 - La Evaluación</title><content type='html'>Retomamos el lenguaje de script miniSL. Hasta ahora hemos definido los datos sobre los que vamos a tratar (&lt;a href="http://elmanantialdebits.blogspot.com/2010/10/minisl-parte-3-celdas.html"&gt;las celdas&lt;/a&gt;) y hemos implementado las operaciones básicas sobre ellos: &lt;a href="http://elmanantialdebits.blogspot.com/2011/02/minisl-parte-9-imprimiendo-celdas.html"&gt;creación&lt;/a&gt; y &lt;a href="http://elmanantialdebits.blogspot.com/2011/01/minisl-parte-7-las-cadenas-internas.html"&gt;destrucción&lt;/a&gt;. También hemos destacado algunos datos como el entorno global.&lt;br /&gt;&lt;br /&gt;Ahora vamos a implementar la principal operación a realizar sobre los datos: tomar una celda que represente una expresión y calcular su valor (que será otra celda). Esto es lo que se llama la &lt;strong&gt;evaluación&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;Existen varios modelos de evaluación. Aquí nos centraremos en la evaluación por entornos (se explica &lt;a href="http://www.mis.yuntech.edu.tw/~tungsh/lasc.pdf"&gt;aquí&lt;/a&gt; y &lt;a href="http://www.cs.bham.ac.uk/~udr/popl/handout1008.pdf"&gt;aquí&lt;/a&gt;). Este tipo de evaluación es realmente sencilla: si queremos saber el valor de una variable, hemos de buscarla en el entorno actual. Si no, buscamos en el entorno padre y así sucesivamente. Esto lo hace la función &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;FindName()&lt;/span&gt; que se vio en la &lt;a href="http://elmanantialdebits.blogspot.com/2011/02/minisl-parte-10-extraccion-de-valores.html"&gt;parte 10&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;La evaluación de literales es inmediata: representan su propio valor (el &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;5&lt;/span&gt; es el 5, la cadena &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;“hola”&lt;/span&gt; es la cadena “hola”). La evaluación de &lt;a href="http://elmanantialdebits.blogspot.com/2010/10/minisl-parte-4-sintaxis.html"&gt;combinaciones&lt;/a&gt; (aplicaciones de una función a argumentos) procede de la siguiente manera.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Se evalúa el operador (la función).&lt;/li&gt;&lt;li&gt;Se envían los operandos sin evaluar a la función.&lt;/li&gt;&lt;/ol&gt;Como hay dos tipos de funciones: la definida por el usuario y la nativa, tendremos que contemplar ambos casos. En principio, la definida por el usuario evaluará los operandos; pero veremos que las nativas necesitan sus operandos sin evaluar (en las partes 29,30 y siguientes).&lt;br /&gt;&lt;br /&gt;La evaluación de una lista es la lista de sus miembros evaluados. Así, &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;[1+2,5]&lt;/span&gt; es la lista [3,5]. La lista vacía es precisamente un literal porque no hay que evaluar nada para calcular su valor.&lt;br /&gt;&lt;br /&gt;Cualquier otra celda no es considerada expresión y genera un error de ejecución.&lt;br /&gt;&lt;br /&gt;El código de la función de evaluación es el siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL&amp;amp; Script::Evaluate(CELL&amp;amp; c, CELL&amp;amp; envir)&lt;br /&gt;{&lt;br /&gt; CELL* aux;&lt;br /&gt; switch(c.type)&lt;br /&gt; {&lt;br /&gt;  //Non evaluable&lt;br /&gt; case UNUSED: throw L"Evaluating an unused cell";&lt;br /&gt; default:  throw L"Evaluating an unknown cell";&lt;br /&gt; case LAMBDA_VAL:throw L"Evaluating a lambda value";&lt;br /&gt; case NATIVE_VAL:throw L"Evaluating a native";&lt;br /&gt; case ENVIR_VAL: throw L"Evaluating an environment";&lt;br /&gt;&lt;br /&gt;  //Literals&lt;br /&gt; case INT_LIT: case BOOL_VAL: case STRING_LIT: case EMPTY_LIT:&lt;br /&gt;  return c;&lt;br /&gt;&lt;br /&gt;  //Code constructors&lt;br /&gt; case CONS_CTOR:  return CreateCell(CONS_CTOR, &amp;amp;Evaluate(*c.head, envir), &amp;amp;Evaluate(*c.tail, envir));&lt;br /&gt;&lt;br /&gt; case NAME_CODE: &lt;br /&gt;  if((aux=FindName(c, envir))==NULL)&lt;br /&gt;   throw L"Unknown name";&lt;br /&gt;  return *aux;&lt;br /&gt;&lt;br /&gt; case COMBINE_CODE:&lt;br /&gt;  switch((aux=&amp;amp;Evaluate(*c.op, envir))-&amp;gt;type)&lt;br /&gt;  {&lt;br /&gt;  case LAMBDA_VAL: return ApplyLambda(*aux-&amp;gt;code, *c.operands, *aux-&amp;gt;closure, envir);&lt;br /&gt;  case NATIVE_VAL: return aux-&amp;gt;native(*this, *c.operands, envir);&lt;br /&gt;  default:   throw L"Non-combinable value";&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Lo más complejo es la evaluación de la combinación. Esto es debido a los casos antes mencionados. Cuando tenemos una operación nativa, directamente llamamos a la función que la implementa. Si tenemos una operación definida por el usuario (lambda) usaremos una función auxiliar &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;ApplyLambda()&lt;/span&gt; que veremos en la siguiente parte de esta serie.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-6558636770448980580?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/6558636770448980580/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/08/minisl-parte-14-la-evaluacion.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6558636770448980580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6558636770448980580'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/08/minisl-parte-14-la-evaluacion.html' title='miniSL parte 14 - La Evaluación'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-6610491883004405030</id><published>2011-07-09T10:56:00.000+02:00</published><updated>2011-07-09T10:56:39.427+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='varios'/><title type='text'>The vessel with the pestle</title><content type='html'>Como me he tomado algunas vacaciones, estoy buscando y viendo algunas de las películas que me gustaron de niño. Las veo en versión original para practicar el inglés. Realmente me he encontrado con algunas sorpresas muy agradables. Por ejemplo, he encontrado esta joya.&lt;br /&gt;&lt;br /&gt;Activad los subtítulos donde pone CC.&lt;br /&gt;&lt;br /&gt;Algunas palabrejas poco usuales del inglés que se usan en este contexto son:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Vessel: vasija&lt;/li&gt;&lt;li&gt;Pestle: mortero&lt;/li&gt;&lt;li&gt;Pellet: pastilla&lt;/li&gt;&lt;li&gt;Flagon: jarra&lt;/li&gt;&lt;li&gt;Brew: brebaje&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;iframe allowfullscreen="" frameborder="0" height="349" src="http://www.youtube.com/embed/W3QYkUaILOI" width="560"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-6610491883004405030?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/6610491883004405030/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/07/vessel-with-pestle.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6610491883004405030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6610491883004405030'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/07/vessel-with-pestle.html' title='The vessel with the pestle'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://img.youtube.com/vi/W3QYkUaILOI/default.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-382216448649501000</id><published>2011-06-29T11:25:00.000+02:00</published><updated>2011-06-29T11:25:44.373+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='algoritmos'/><title type='text'>Números binarios en C++</title><content type='html'>En C++ (y en C y en otros muchos lenguajes de programación) hay tres formas de escribir &lt;a href="http://www.blogger.com/"&gt;&lt;span id="goog_1393480983"&gt;&lt;/span&gt;números enteros literales&lt;span id="goog_1393480984"&gt;&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;En base 10 (decimal) cuando escribo algo como 1042348&lt;/li&gt;&lt;li&gt;En base 16 (hexadecimal) cuando prefijo 0x como en 0x3FFF&lt;/li&gt;&lt;li&gt;En base 8 (octal) cuando prefijo sólo 0 como en 0663&lt;/li&gt;&lt;/ol&gt;Cuando se programa en bajo nivel muchas veces es más directo escribir directamente en base 2 (binario), ¿pero cómo? Me he &lt;a href="http://c-faq.com/misc/sd28.html"&gt;topado&lt;/a&gt; con la siguiente macro que lo consigue&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;#define Ob(x)  ((unsigned)Ob_(0 ## x ## uL))&lt;br /&gt;#define Ob_(x) (x &amp;amp; 1 | x &amp;gt;&amp;gt; 2 &amp;amp; 2 | x &amp;gt;&amp;gt; 4 &amp;amp; 4 | x &amp;gt;&amp;gt; 6 &amp;amp; 8 |  \&lt;br /&gt; x &amp;gt;&amp;gt; 8 &amp;amp; 16 | x &amp;gt;&amp;gt; 10 &amp;amp; 32 | x &amp;gt;&amp;gt; 12 &amp;amp; 64 | x &amp;gt;&amp;gt; 14 &amp;amp; 128)&lt;/pre&gt;&lt;br /&gt;El truco se basa en dos pasos, el primero &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;Ob&lt;/span&gt; (no es un cero, es una o) pone delante un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;0&lt;/span&gt; (que sí es un cero) y detrás un "uL". El "uL" es la forma que tenemos de decirle al C++ que el número es sin signo y largo. El cero, por otra parte, sí que es importante ya que nos va a convertir el número a octal. Lo que tenemos entonces es un número binario interpretado como un número octal. ¿Cómo afecta eso a su valor?&lt;br /&gt;&lt;br /&gt;Un número binario se expresa de la siguiente forma [$$ n=\cdots + d_3 2^3 + d_2 2^2 + d_1 2^1  + d_0 2^0 $$] donde los [$d_i$] son los dígitos. Los dígitos serán o cero o uno. Al escribir el número binario como octal lo que hacemos es&amp;nbsp;  [$$ n=\cdots + d_3 8^3 + d_2 8^2 + d_1 8^1  + d_0 8^0 $$] pero aún con los dígitos en binario. Así que lo único que necesitamos es leer los bits de tres en tres ya que [$8=2^3$]. &amp;nbsp;Justamente eso es lo que hace &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;Ob_&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Por ejemplo:&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;Ob(1001) //Como binario es 9 en decimal&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;Ob_(01001uL) //Como octal es 513 en decimal y 1_000_000_001 en binario&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;9 //Tomando un bit de cada 3 en el 513&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-382216448649501000?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/382216448649501000/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/06/numeros-binarios-en-c.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/382216448649501000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/382216448649501000'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/06/numeros-binarios-en-c.html' title='Números binarios en C++'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-1191545297843943451</id><published>2011-06-23T11:12:00.000+02:00</published><updated>2011-06-23T11:12:02.178+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='varios'/><category scheme='http://www.blogger.com/atom/ns#' term='ingeniería del software'/><title type='text'>Clasificación de los bugs</title><content type='html'>Leyendo a &lt;a href="http://drdobbs.com/blogs/tools/230700070"&gt;Walter Bright&lt;/a&gt; me he encontrado con la palabreja "heisenbug" que según él es un tipo de bug. Ya me imaginaba yo que tendría que haber una taxonomía de los bugs. El resumen de lo que he &lt;a href="http://www.catb.org/jargon/html/index.html"&gt;encontrado&lt;/a&gt; es este:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Bohrbug&lt;/strong&gt;: Error sistemático que se da siempre cuando las condiciones lo propician.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Mandelbug&lt;/strong&gt;: Error sistemático tan complejo que no parece sistemático, pero lo es.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Heisenbug&lt;/strong&gt;: Error sistemático que desaparece cuando intentamos depurarlo. Ya sea por que estamos usando el depurador y cambia la estructura de la memoria, porque el código está compilado en modo de depuración o por otras razones.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Schrödinbug&lt;/strong&gt;: Error oculto que, una vez descubierto, todo el mundo se tropieza con él.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Estadístico&lt;/strong&gt;: Error que no se detecta en una única ejecución del programa, sino que hay que hacer una estadística de los resultados hasta darnos cuenta que no son como deberían ser. (Esto me recuerda a la &lt;a href="http://www.gamasutra.com/view/feature/2816/better_game_design_through_data_.php"&gt;minería de datos en los MMORPG&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Alfa bug&lt;/strong&gt;: Error que ves una vez y no vuelves a ver. Lo que ocurría antiguamente cuando &lt;a href="http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=1479948"&gt;un rayo cósmico le daba a una celda de memoria&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;Supongo que luego están los errores de &lt;a href="http://es.wikipedia.org/wiki/Condici%C3%B3n_de_carrera"&gt;condiciones de carrera&lt;/a&gt;, que aparecen cuando les da la gana si no se han sincronizado bien las hebras. Ya inventarán una palabreja para eso algún día.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-1191545297843943451?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/1191545297843943451/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/06/clasificacion-de-los-bugs.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/1191545297843943451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/1191545297843943451'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/06/clasificacion-de-los-bugs.html' title='Clasificación de los bugs'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-5612402136569976089</id><published>2011-06-17T10:41:00.000+02:00</published><updated>2011-06-17T10:41:56.712+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='matemáticas'/><title type='text'>El lío de las composiciones</title><content type='html'>&lt;b&gt;&lt;span style="color: red;"&gt;La composición en las relaciones&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Una &lt;a href="http://es.wikipedia.org/wiki/Relaci%C3%B3n_binaria"&gt;relación&lt;/a&gt; [$\le$] entre [$A$] y [$B$] es un subconjunto del conjunto cartesiano.[$$\le \subseteq A\times B$$]Cuando dos elementos [$a\in A$] y [$b\in B$] están relacionados escribimos [$$ a \le b \Leftrightarrow (a,b)\in \le$$] La &lt;a href="http://en.wikipedia.org/wiki/Relation_composition"&gt;composición&lt;/a&gt; de dos relaciones [$\le_1$] entre [$A$] y [$B$]; y [$\le_2$] entre [$B$] y [$C$] es [$\le_1 \circ \le_2$] definida así [$$ a \le_1\circ \le_2 c \Leftrightarrow \exists b\in B.a\le_1 b\le_2 c $$] Es interesante ver el parecido natural entre [$$&amp;nbsp; a \le_1\circ \le_2 c$$] y [$$ a\le_1 b\le_2 c $$] como si el [$\circ$] representase un elemento indefinido a buscar.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;La composición en las funciones&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Una &lt;a href="http://es.wikipedia.org/wiki/Funci%C3%B3n_matem%C3%A1tica"&gt;función&lt;/a&gt; [$f:A\to B$] no es más que una relación en la cual [$$\forall a\in A.\exists ! b\in B. a f b $$] Para los que no lo hayan visto nunca [$\exists !$] significa "existe un único".&lt;br /&gt;Bien, los problemas empiezan porque si existe un único [$b$] lo natural es representarlo por [$f$] y [$a$]. La forma de hacerlo es esta: [$$f(a)=b \Leftrightarrow a f b$$] ¿Por qué es problemático? Porque si pienso que una función es una relación y defino la &lt;a href="http://es.wikipedia.org/wiki/Funci%C3%B3n_compuesta"&gt;composición de funciones&lt;/a&gt; como una composición de relaciones obtenemos [$$ (f\circ g)(a)=g(f(a)) $$] Invirtiéndose el orden de [$f$] y [$g$], lo que lía muchísimo. Así que lo que se hace es &lt;strong&gt;definir al revés&lt;/strong&gt; la composición de funciones. [$$ (f\circ g)(a)=f(g(a)) $$] Por lo que deja de ser igual que la composición de relaciones.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Soluciones&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Las que se me ocurren así a bote pronto son:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Usar una notación &lt;a href="http://elmanantialdebits.blogspot.com/2011/04/infija-prefija-postfija-y-circunfija.html"&gt;postfija&lt;/a&gt; para las funciones [$(a)f$] en vez de [$f(a)$]. De esta manera [$ (a)(f\circ g) &amp;nbsp;=((a)f)g$] y el orden coincide con la composición de relaciones.&lt;/li&gt;&lt;li&gt;Invertir una de las dos composiciones. O bien [$ (f\circ g)(a)=g(f(a)) $] o bien [$ a \le_2\circ \le_1 c \Leftrightarrow \exists b\in B.a\le_1 b\le_2 c $]. Hagas lo que hagas, estás invirtiendo el orden natural de la notación y vas a liarte (el elemento [$a$] va primero a [$f$] y a [$\le_1$] que están lejos de él).&lt;/li&gt;&lt;li&gt;Usar dos notaciones. Por ejemplo, usar [$\le_1 ; \le_2 = \le_2 \circ \le_1$] y [$ f \circ g = g ; f $]. Esta solución la suele usar alguno que otro autor.&lt;/li&gt;&lt;li&gt;Definir las funciones al revés, [$\forall a\in A.\exists ! b\in B. b f a $] de forma que &amp;nbsp; [$b=f(a) \Leftrightarrow b f a$]. Claro que también así vamos en contra de unos cuantos siglos de historia y habría que darle la vuelta a muchas definiciones como relaciones inyectivas.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-5612402136569976089?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/5612402136569976089/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/06/el-lio-de-las-composiciones.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/5612402136569976089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/5612402136569976089'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/06/el-lio-de-las-composiciones.html' title='El lío de las composiciones'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-2022473876986679568</id><published>2011-06-09T11:29:00.000+02:00</published><updated>2011-06-09T11:29:28.288+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='matemáticas'/><title type='text'>Exponenciando la derivación</title><content type='html'>Realmente para definir la &lt;a href="http://en.wikipedia.org/wiki/Exponential_function"&gt;exponencial&lt;/a&gt; (o cualquier otra &lt;a href="http://en.wikipedia.org/wiki/Analytic_function"&gt;función analítica&lt;/a&gt;) mediante una &lt;a href="http://en.wikipedia.org/wiki/Power_series"&gt;serie de potencias&lt;/a&gt; hacen falta pocas cosas.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Una operación de multiplicación por escalar&lt;/li&gt;&lt;li&gt;Una operación de suma&lt;/li&gt;&lt;li&gt;Una operación de potencia&lt;/li&gt;&lt;/ul&gt;Con estas tres operaciones podemos definir&lt;br /&gt;[$$ e^x = \sum_{k=0}^\infty \frac{x^k}{k!} $$]&lt;br /&gt;Los operadores lineales cumplen todas estas condiciones tomando la potencia como composición iterada.&lt;br /&gt;[$$f^0=Id; &amp;nbsp;f^{n+1}=f\circ f^n$$]&lt;br /&gt;Un caso clásico es cuando las operaciones lineales están representadas por &lt;a href="http://en.wikipedia.org/wiki/Matrix_exponential"&gt;matrices&lt;/a&gt;.&lt;br /&gt;Otro de estos operadores lineales es la derivación, que escribiremos [$D$]. Se puede realizar la exponencial de la derivación.&lt;br /&gt;[$$e^D = \sum_{k=0}^\infty \frac{D^k}{k!} $$]&lt;br /&gt;Para ver mejor sus efectos, aplicaremos el resultado de [$\alpha$] veces esta exponencial sobre [$x^n$].&lt;br /&gt;[$$e^{\alpha D} x^n = \sum_{k=0}^\infty \frac{\alpha^k D^k}{k!} x^n $$]&lt;br /&gt;Podemos derivar hasta [$n$] veces [$x^n$]&lt;br /&gt;[$$\sum_{k=0}^n \frac{n!&amp;nbsp; \alpha^k x^{n-k} }{k! (n-k)!}$$]&lt;br /&gt;Es interesantísimo ver que lo obtenido es justamente el &lt;a href="http://en.wikipedia.org/wiki/Newton_binomial"&gt;binomio de Newton&lt;/a&gt;.&lt;br /&gt;[$$ \sum_{k=0}^n \frac{n!&amp;nbsp; \alpha^k x^{n-k} }{k! (n-k)!} = (x+\alpha)^n $$]&lt;br /&gt;Debido a que estamos trabajando con operadores lineales, podemos volver a usar una serie de potencias para aplicar la exponencial de la derivación sobre una función analítica arbitraria.&lt;br /&gt;[$$ (e^{\alpha D} f)(x) = e^{\alpha D} \sum_{i=0}^\infty {a_i x^i} = &amp;nbsp; \sum_{i=0}^\infty {a_i &amp;nbsp; e^{\alpha D} x^i} =&amp;nbsp; \sum_{i=0}^\infty {a_i &amp;nbsp;(x+\alpha)^i} = f(x+\alpha) $$]&lt;br /&gt;Así que la exponencial de la derivación no es más que una traslación.&lt;br /&gt;Los físicos me dicen que acabo de descubrir que el &lt;a href="http://en.wikipedia.org/wiki/Momentum_operator"&gt;operador de momento&lt;/a&gt; genera las traslaciones. ¡Vaya! Pues no lo sabía.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-2022473876986679568?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/2022473876986679568/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/06/exponenciando-la-derivacion.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/2022473876986679568'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/2022473876986679568'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/06/exponenciando-la-derivacion.html' title='Exponenciando la derivación'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-2293459857565793776</id><published>2011-05-26T15:53:00.001+02:00</published><updated>2011-06-23T11:16:04.679+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='video y gráficos'/><category scheme='http://www.blogger.com/atom/ns#' term='matemáticas'/><title type='text'>Espacios proyectivos</title><content type='html'>&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;&lt;span style="color: red;"&gt;&lt;b&gt;Espacio Vectorial&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;&lt;span style="color: red;"&gt;&lt;b&gt;Espacio Proyectivo&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;[$\mathbb{R}^2$]&lt;/td&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;[$P(\mathbb{R})$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Los elementos de [$\mathbb{R}^2$], en coordenadas cartesianas, son pares de números reales [$(x,y)$] que representan puntos.&lt;/td&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Los elementos de [$P(\mathbb{R})$], en coordenadas homogéneas, son pares de números reales [$(x,y)$] que representan rectas que pasan por el origen.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/--G5wjaNH2eY/Td5WAbOUz2I/AAAAAAAAAH0/SjbKQCcb1ZQ/s1600/EspaciosProyectivos1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="151" src="http://2.bp.blogspot.com/--G5wjaNH2eY/Td5WAbOUz2I/AAAAAAAAAH0/SjbKQCcb1ZQ/s200/EspaciosProyectivos1.png" width="200" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-XnfN-isEpHE/Td5WBFMMGAI/AAAAAAAAAH4/TzTo0pejq7Q/s1600/EspaciosProyectivos2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="151" src="http://3.bp.blogspot.com/-XnfN-isEpHE/Td5WBFMMGAI/AAAAAAAAAH4/TzTo0pejq7Q/s200/EspaciosProyectivos2.png" width="200" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Dos puntos [$P=(x,y)$] y [$P'=(x',y')$] son iguales si y sólo si&lt;br /&gt;[$$x=x',\ y=y'$$]&lt;br /&gt;y lo escribiremos [$P=P'$].&lt;/td&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Dos puntos [$P=(x,y)$] y [$P'=(x',y')$] están en la misma recta si y sólo si existe un [$k\in\mathbb{R}$] tal que&lt;br /&gt;[$$x=kx',\ y=ky'$$]&lt;br /&gt;y lo escribiremos [$P\equiv P'$].&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;[$$\mathbb{R}^2=\{(x,y)∣x,y\in\mathbb{R}\}$$]&lt;/td&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;[$$P(\mathbb{R})=(\mathbb{R}^2-\{(0,0)\})/\equiv $$]&lt;br /&gt;Si [$x=y=0$] no tenemos una recta por eso se ha excluido el punto [$(0,0)$] que no forma una recta.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Cada punto tiene dos grados de libertad, la abscisa [$x$] y la ordenada [$y$].&lt;/td&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Cada recta sólo tiene un grado de libertad. La equivalencia entre rectas [$\equiv$] le quita un grado de libertad a [$(x,y)$] (precisamente, es el valor de [$k$] que hemos de hallar).&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Usar una matriz para transformar puntos en otros genera aplicaciones lineales.&lt;br /&gt;[$$P'=AP$$]&lt;/td&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Usar una matriz para transformar rectas en otras genera colineaciones.&lt;br /&gt;[$$P'≡AP$$]&lt;br /&gt;Es decir, existe un [$k\in\mathbb{R}$] tal que&lt;br /&gt;[$$P'=kAP$$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Una matriz tiene cuatro grados de libertad cuando representa una aplicación lineal.&lt;/td&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Una matriz tiene tres grados de libertad cuando representa una colineación.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-Hjbdefh9dmk/Td5Y5oW2SWI/AAAAAAAAAH8/2QKQHd2818g/s1600/EspaciosProyectivos3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="148" src="http://2.bp.blogspot.com/-Hjbdefh9dmk/Td5Y5oW2SWI/AAAAAAAAAH8/2QKQHd2818g/s200/EspaciosProyectivos3.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-hByR9GunBpg/Td5Y6hL4pPI/AAAAAAAAAIA/3sbrhZgWZ1k/s1600/EspaciosProyectivos4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="148" src="http://2.bp.blogspot.com/-hByR9GunBpg/Td5Y6hL4pPI/AAAAAAAAAIA/3sbrhZgWZ1k/s200/EspaciosProyectivos4.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Si la matriz es regular (no singular, con determinante no nulo), la transformación lineal es invertible.&lt;/td&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Si la matriz es regular, la colineación se denomina homografía y representa proyecciones cónicas.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Al ser invertible forma un grupo. Concretamente el [$GL(2,\mathbb{R})$].&lt;/td&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Al ser invertible forma un grupo.&lt;br /&gt;Concretamente el [$PGL(2,\mathbb{R})$].&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;&lt;/td&gt;&amp;nbsp;&lt;td style="border: 1px solid; text-align: center;"&gt;Es posible y deseable normalizar los puntos. Una forma de hacerlo es elegir de cada recta el punto cuya última coordenada sea uno. En este caso [$y=1$].&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-MEKDzTKlK0I/Td5Z1fnikqI/AAAAAAAAAIE/uKCOGricUrk/s1600/EspaciosProyectivos5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="148" src="http://3.bp.blogspot.com/-MEKDzTKlK0I/Td5Z1fnikqI/AAAAAAAAAIE/uKCOGricUrk/s200/EspaciosProyectivos5.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;Esto se consigue eligiendo [$k$] adecuadamente.&lt;br /&gt;[$$(x,y)≡k(x,y)=\frac{1}{y}(x,y)=(\frac{x}{y},1)$$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;&lt;/td&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Se comprueba con facilidad que esta normalización es una proyección perspectiva donde la línea [$y=1$] es el plano de proyección.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-2-8JmiNqzr4/Td5agi_Vy5I/AAAAAAAAAII/Ll64QlkmP8U/s1600/EspaciosProyectivos6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="112" src="http://3.bp.blogspot.com/-2-8JmiNqzr4/Td5agi_Vy5I/AAAAAAAAAII/Ll64QlkmP8U/s200/EspaciosProyectivos6.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Todo esto se puede extender a 3 dimensiones usando [$\mathbb{R}^3$].&lt;/td&gt;&lt;td style="border: 1px solid; text-align: center;"&gt;Todo esto se puede extender de proyectar en una línea en [$P(\mathbb{R})$] a proyectar en un plano en [$P^2(\mathbb{R})$]. Este plano sería, por ejemplo, la pantalla del monitor o el CCD de una cámara.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-2293459857565793776?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/2293459857565793776/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/05/espacios-proyectivos.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/2293459857565793776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/2293459857565793776'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/05/espacios-proyectivos.html' title='Espacios proyectivos'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/--G5wjaNH2eY/Td5WAbOUz2I/AAAAAAAAAH0/SjbKQCcb1ZQ/s72-c/EspaciosProyectivos1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-9205854311475844464</id><published>2011-05-23T14:59:00.000+02:00</published><updated>2011-05-23T14:59:12.151+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='miniSL'/><title type='text'>miniSL parte 13 - El entorno global</title><content type='html'>En la &lt;a href="http://elmanantialdebits.blogspot.com/2011/04/minisl-parte-12-limitaciones-y-uso-del.html"&gt;parte anterior de esta serie&lt;/a&gt; hablamos del entorno global como conjunto raíz del recolector de basura. El código relacionado está en la parte octava de esta serie, en la función GarbageCollect(). También dijimos que el entorno global no es más que una celda destacada.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL* m_GlobalEnvir;&lt;/pre&gt;La creación de esa celda se va a realizar cuando iniciemos todo el sistema del lenguaje script. En el constructor de la clase Script.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;Script() : m_FirstUnused(NULL) { m_GlobalEnvir=&amp;amp;CreateEnvir(NULL); }&lt;/pre&gt;Recordemos que &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;m_FirstUnused&lt;/span&gt; se usaba para reutilizar las celdas recicladas por el recolector de basura.&lt;br /&gt;&lt;br /&gt;Lo importante es que &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;m_GlobalEnvir&lt;/span&gt; no va a cambiar y siempre va a ser un entorno. Vimos la función &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;CreateEnvir()&lt;/span&gt; en &lt;a href="http://elmanantialdebits.blogspot.com/2011/03/minisl-parte-10-operaciones-sobre-el.html"&gt;la parte 11&lt;/a&gt;. En la &lt;a href="http://elmanantialdebits.blogspot.com/2010/11/minisl-parte-6-campos-de-celda.html"&gt;parte 6&lt;/a&gt; explicamos que una celda de entorno (de tipo &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;ENVIR_VAL&lt;/span&gt;) sólo tiene un puntero a una tabla hash o árbol de búsqueda así que, como lo que vamos a hacer con este entorno es definir símbolos en él,  sera muy útil obtener directamente la tabla del entorno global.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;ENVIR_TABLE&amp;amp; GlobalEnvirTable()const { return *m_GlobalEnvir-&amp;gt;envir_table; }&lt;/pre&gt;La mayor parte de símbolos que vamos a definir en la tabla del entorno global son operaciones nativas. La función &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;DefineGlobalNative()&lt;/span&gt; nos ahorra tener que llamar a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;CreateName()&lt;/span&gt; y &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;CreateNative()&lt;/span&gt; cada vez.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;void DefineGlobalNative(STRING const&amp;amp; name, NATIVE nat)&lt;br /&gt; {&lt;br /&gt;  (*m_GlobalEnvir-&amp;gt;envir_table)[&amp;amp;CreateName(name)]=&amp;amp;CreateNative(nat);&lt;br /&gt; }&lt;/pre&gt;Finalmente, poblaremos la tabla del entorno global con la función &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;DefineUsualSymbols()&lt;/span&gt;. Se declara así en la clase Script.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;void DefineUsualSymbols();&lt;/pre&gt;Y se define así.&lt;br /&gt;&lt;pre class="brush:cpp"&gt;void Script::DefineUsualSymbols()&lt;br /&gt;{&lt;br /&gt; DefineGlobalNative(L"=", &amp;amp;Native_Set);&lt;br /&gt;&lt;br /&gt; DefineGlobalNative(L"+", &amp;amp;Native_Add);&lt;br /&gt; DefineGlobalNative(L"-", &amp;amp;Native_Sub);&lt;br /&gt; DefineGlobalNative(L"*", &amp;amp;Native_Mul);&lt;br /&gt; DefineGlobalNative(L"&amp;amp;", &amp;amp;Native_BAnd);&lt;br /&gt; DefineGlobalNative(L"|", &amp;amp;Native_BOr);&lt;br /&gt; DefineGlobalNative(L"^", &amp;amp;Native_BXor);&lt;br /&gt;&lt;br /&gt; DefineGlobalNative(L"/", &amp;amp;Native_Div);&lt;br /&gt; DefineGlobalNative(L"%", &amp;amp;Native_Mod);&lt;br /&gt;&lt;br /&gt; DefineGlobalNative(L"==", &amp;amp;Native_Eq);&lt;br /&gt; DefineGlobalNative(L"!=", &amp;amp;Native_Ne);&lt;br /&gt; DefineGlobalNative(L"&amp;lt;", &amp;amp;Native_Lt);&lt;br /&gt; DefineGlobalNative(L"&amp;lt;=", &amp;amp;Native_Le);&lt;br /&gt; DefineGlobalNative(L"&amp;gt;", &amp;amp;Native_Gt);&lt;br /&gt; DefineGlobalNative(L"&amp;gt;=", &amp;amp;Native_Ge);&lt;br /&gt;&lt;br /&gt; DefineGlobalNative(L"if", &amp;amp;Native_If);&lt;br /&gt; DefineGlobalNative(L"let", &amp;amp;Native_Let);&lt;br /&gt; DefineGlobalNative(L"while", &amp;amp;Native_While);&lt;br /&gt; DefineGlobalNative(L"begin", &amp;amp;Native_Begin);&lt;br /&gt; DefineGlobalNative(L"define", &amp;amp;Native_Define);&lt;br /&gt; DefineGlobalNative(L"set", &amp;amp;Native_Set);&lt;br /&gt; DefineGlobalNative(L"lambda", &amp;amp;Native_Lambda);&lt;br /&gt;&lt;br /&gt; (*m_GlobalEnvir-&amp;gt;envir_table)[&amp;amp;CreateName(L"true")]=&amp;amp;CreateBool(true);&lt;br /&gt; (*m_GlobalEnvir-&amp;gt;envir_table)[&amp;amp;CreateName(L"false")]=&amp;amp;CreateBool(false);&lt;br /&gt;}&lt;/pre&gt;La mayoría de estas funciones nativas (hemos prefijado el nombre con &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;Native_&lt;/span&gt; para distinguirlas claramente) todavía no están definidas. Lo haremos en las partes de la 26 a la 31.&lt;br /&gt;Antes nos vamos a dedicar a la evaluación, puesto que tenemos ya especificado todo lo que hace falta para explicarla.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-9205854311475844464?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/9205854311475844464/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/05/minisl-parte-13-el-entorno-global.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/9205854311475844464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/9205854311475844464'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/05/minisl-parte-13-el-entorno-global.html' title='miniSL parte 13 - El entorno global'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-3680905206915290152</id><published>2011-05-11T10:41:00.002+02:00</published><updated>2011-05-11T10:45:05.853+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teoria de tipos'/><category scheme='http://www.blogger.com/atom/ns#' term='iteradores'/><category scheme='http://www.blogger.com/atom/ns#' term='programación genérica'/><category scheme='http://www.blogger.com/atom/ns#' term='calculabilidad'/><category scheme='http://www.blogger.com/atom/ns#' term='semántica formal'/><title type='text'>El punto de la pereza</title><content type='html'>Hace unos días &lt;a href="http://www.cs.cmu.edu/~rwh/"&gt;Bob Harper&lt;/a&gt;, que defiende &lt;a href="http://en.wikipedia.org/wiki/Standard_ML"&gt;SML&lt;/a&gt; con uñas y dientes, se dedicó a &lt;a href="http://existentialtype.wordpress.com/2011/04/24/the-real-point-of-laziness/"&gt;atacar a los elitistas del Haskell&lt;/a&gt;. Su idea era muy sencilla: los tipos de &lt;a href="http://www.haskell.org/haskellwiki/Haskell"&gt;Haskell&lt;/a&gt; no son inductivos. Voy a intentar explicar esto de forma sencilla.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;Tipos inductivos&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Son los tipos cuyos valores se construyen con unos valores bases y unos constructores. El caso arquetípico son los números naturales.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;El &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;0&lt;/span&gt; es un valor base.&lt;/li&gt;&lt;li&gt;El siguiente número natural &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;S(n)&lt;/span&gt;, es un constructor que, dado un número, construye otro.&lt;/li&gt;&lt;/ul&gt;Con esto y la &lt;a href="http://www.mat.puc.cl/~ldissett/cursos/iic2252-022/clase22.pdf"&gt;inducción estructural&lt;/a&gt; tenemos los números naturales (y podemos demostrar propiedades sobre ellos).&lt;br /&gt;&lt;ul&gt;&lt;li&gt;El cero es &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;0&lt;/span&gt;&lt;/li&gt;&lt;li&gt;El uno es &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;S(0)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;El dos es &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;S(S(0))&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Y así.&lt;/li&gt;&lt;/ul&gt;También es posible usar como argumento de un constructor el valor de otro tipo. Este otro tipo será un parámetro del nuevo tipo. De esa manera aterrizamos en los &lt;a href="http://www.fceia.unr.edu.ar/lcc/t321/archivos/10.ALPII.Clase02.pdf"&gt;tipos algebraicos&lt;/a&gt;. Por ejemplo, las listas de valores de un tipo T que llamaremos L(T) será.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;La lista vacía [] es un valor base.&lt;/li&gt;&lt;li&gt;El constructor de lista &amp;nbsp;cons(V,R) toma un valor V de un tipo T y el resto de la lista R de tipo L(T).&lt;/li&gt;&lt;/ul&gt;Con esto y la inducción estructural, obtenemos las listas que queramos (y podemos demostrar propiedades sobre ellas).&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Tomamos la lista vacía [] como valor base de una lista de enteros L(int)&lt;/li&gt;&lt;li&gt;Añadimos &amp;nbsp;un entero &amp;nbsp;cons(-3, [])&lt;/li&gt;&lt;li&gt;Añadimos otro entero &amp;nbsp;cons(7, cons(-3, []) )&lt;/li&gt;&lt;/ul&gt;Todos estos tipos inductivos tienen una forma muy similar si se dibujan: son bosques de árboles (matemáticamente son &lt;a href="http://en.wikipedia.org/wiki/Complete_partial_order"&gt;órdenes parciales completos&lt;/a&gt;, también llamados dominios). En concreto, los números naturales son un árbol de una única rama.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-4oYIxdDBu7M/Tco9gPmAu8I/AAAAAAAAAHI/Sfn9814t2pg/s1600/NaturalesInductivos.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://2.bp.blogspot.com/-4oYIxdDBu7M/Tco9gPmAu8I/AAAAAAAAAHI/Sfn9814t2pg/s320/NaturalesInductivos.png" width="156" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Los números naturales son inductivos. El valor base es el 0, en un círculo, y el constructor es S(n), en rectángulos. De esta manera tenemos representados en la figura, de abajo arriba, los valores 0, S(0), S(S(0)), S(S(S(0))) y así sucesivamente.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Los booleanos son dos árboles sin ramas.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-X_ogRnm9VGk/Tco-hbRNKvI/AAAAAAAAAHM/AFs2jnKccqM/s1600/BooleanosInductivos.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-X_ogRnm9VGk/Tco-hbRNKvI/AAAAAAAAAHM/AFs2jnKccqM/s1600/BooleanosInductivos.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Los booleanos son dos valores base: true y false. No hay constructores. Estos tipos sin constructores suelen llamarse &lt;a href="http://en.wikipedia.org/wiki/Enumerated_type"&gt;tipos enumerados&lt;/a&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Las listas de naturales son árboles con infinitas ramas ya que, cada vez que usamos un constructor con un natural distinto, generamos una nueva rama. Es difícil dibujar esto porque cada una de las infinitas ramas lleva a infinitos valores que, a su vez, vuelven a tener infinitas ramas. Con un poco de imaginación el diagrama sería algo así.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-4l1kAYvHK74/Tco_c7JNykI/AAAAAAAAAHQ/OPi9zhfSwLE/s1600/ListaInductiva.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="183" src="http://3.bp.blogspot.com/-4l1kAYvHK74/Tco_c7JNykI/AAAAAAAAAHQ/OPi9zhfSwLE/s320/ListaInductiva.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Lista de naturales. La lista vacía es el valor base [] que está abajo. A partir de él construimos infinitos valores, uno para cada natural. Serían las listas de un único natural. Asimismo, de cada uno de estos valores se obtienen otros infinitos valores. A este tipo de árboles infinitos pero con una estructura simple se los denomina &lt;a href="http://en.wikipedia.org/wiki/Regular_tree"&gt;árboles regulares&lt;/a&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Existen también los llamados tipos coinductivos en los cuales, en vez de tener una lista vacía (valores base) y usar constructores sobre ella, tenemos una lista llena (valores co-base) y usamos destructores (co-constructores) sobre ella. No hablaré mucho más de esto aquí.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;Evaluación perezosa&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La evaluación perezosa, de la que &lt;a href="http://elmanantialdebits.blogspot.com/2009/08/estrategias-de-evaluacion.html"&gt;hablamos alguna que otra vez&lt;/a&gt;, consiste básicamente en no evaluar hasta que no sea estrictamente necesario. Un caso clásico es la multiplicación por cero.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;0*(7+5)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;¿Para qué sumar siete y cinco si sabemos que al final la multiplicación va a ser cero? Bueno, existe un motivo por el que evaluar los argumentos y son los efectos laterales. Si en vez de sumar dos números imprimiésemos un mensaje, la cosa cambia.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;0*(print "hola")&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ahora sí que habría que imprimir "hola" aunque el resultado de esta multiplicación (si es que &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;print&lt;/span&gt; devuelve un número, claro) sea cero. Pues bien, ocurre que en Haskell no hay efectos secundarios. Es un &lt;a href="http://users.dsic.upv.es/asignaturas/facultad/prg/prf.html"&gt;lenguaje funcional&lt;/a&gt;. En este lenguaje de programación sí que conviene no perder tiempo evaluando cosas que, al final, no se van a usar.&lt;br /&gt;&lt;br /&gt;La idea fundamental de la crítica de Harper es que siempre existen los efectos secundarios. En concreto existe un efecto secundario que jamás puedes quitarte de encima en un lenguaje de programación &lt;a href="http://es.wikipedia.org/wiki/Turing_completo"&gt;Turing completo&lt;/a&gt;. Ese efecto es... que la computación no termine.&lt;br /&gt;&lt;br /&gt;Imaginemos el siguiente programa:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f(x) = 1+f(x) &amp;nbsp;//Esta computación no termina&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;0*f(3)&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Si el lenguaje es estricto y evalúa &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f(3)&lt;/span&gt;, nunca llega a ejecutar la multiplicación. Si el lenguaje es perezoso y no evalúa &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f(3)&lt;/span&gt;, la multiplicación ha aceptado un valor que no es un número (de hecho ni siquiera es un valor, es no terminación) y lo ha tratado como si fuera un número. ¿Cuál es el tipo del argumento que ha aceptado la multiplicación?&lt;br /&gt;&lt;br /&gt;Los lenguajes con evaluación perezosa cuelan entre los valores de sus tipos la no terminación. O mejor dicho, algo todavía sin evaluar que puede ser no terminación o puede ser un valor concreto. Este valor tan especial que se puede convertir en otro (o no) se corresponde con el mínimo de un orden parcial completo con mínimo. Este mínimo tiene el nombre de "punto" y se suele representar con el símbolo [$\bot$].&lt;br /&gt;&lt;br /&gt;Si añadimos el punto a los tipos inductivos el resultado es que ¡no son inductivos! Los naturales y los booleanos quedan algo así.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-cUiH_iyx5bQ/TcpHLnfm3fI/AAAAAAAAAHU/fYTbyXDAyt0/s1600/BooleanosYNaturalesConPunto.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="236" src="http://3.bp.blogspot.com/-cUiH_iyx5bQ/TcpHLnfm3fI/AAAAAAAAAHU/fYTbyXDAyt0/s320/BooleanosYNaturalesConPunto.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Los naturales y booleanos con punto. El punto representa la no evaluación (con la no terminación como posibilidad). El punto está más allá de la inducción. No se pueden usar técnicas inductivas para demostrar propiedades de él.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;Esto rompe la posibilidad de usar la inducción estructural porque el punto queda más allá, más arriba, del resto de valores. Así que, según Harper, usar la evaluación perezosa es equivalente a olvidarse de la inducción estructural y, con ella, poder demostrar con facilidad múltiples propiedades en nuestro programa.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;Epílogo&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Por supuesto, esto es todo cuestión de compromisos. Usar evaluación perezosa abre la puerta a tener tipos coinductivos con mucha facilidad. De hecho la "lista llena" de la que hablé antes es precisamente el punto [$\bot$]. Una computación que puede no terminar, &lt;a href="http://en.wikibooks.org/wiki/Haskell/More_about_lists#Infinite_Lists"&gt;una lista infinita&lt;/a&gt;, de la cual vamos extrayendo valores, como los iteradores. Esto permite cosas nuevas como el uso de la composición en estos tipos coinductivos, lo que abre la posibilidad a la &lt;a href="http://augustss.blogspot.com/2011/05/more-points-for-lazy-evaluation-in.html"&gt;reutilización de código&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-3680905206915290152?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/3680905206915290152/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/05/el-punto-de-la-pereza.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/3680905206915290152'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/3680905206915290152'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/05/el-punto-de-la-pereza.html' title='El punto de la pereza'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-4oYIxdDBu7M/Tco9gPmAu8I/AAAAAAAAAHI/Sfn9814t2pg/s72-c/NaturalesInductivos.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-6016017440690754719</id><published>2011-05-02T14:05:00.000+02:00</published><updated>2011-05-02T14:05:26.175+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algoritmos'/><category scheme='http://www.blogger.com/atom/ns#' term='matemáticas'/><title type='text'>La multiplicación de Gauss</title><content type='html'>¿Cómo realizar una multiplicación compleja usando sólo tres productos reales?&lt;br /&gt;&lt;br /&gt;La multiplicación usual requiere cuatro:&lt;br /&gt;[$$ (a+bi)(c+di) = ac-bd + (ad+bc)i $$]&lt;br /&gt;El truco lo descubrió Gauss por 1805&lt;br /&gt;[$$ ac-bd = ac +bc -bc -bd = c(a+b) - b(c+d) $$]&lt;br /&gt;[$$ ad+bc = ad +ac-ac +bc = c(a+b) +a(d-c) $$]&lt;br /&gt;&lt;br /&gt;Como vemos, se reusa la multiplicación [$c(a+b)$].&lt;br /&gt;&lt;br /&gt;Esto me lleva a recordar el algoritmo de &lt;a href="http://en.wikipedia.org/wiki/Strassen_algorithm"&gt;Strassen&lt;/a&gt; para multiplicar matrices, pero ese es otro tema.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-6016017440690754719?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/6016017440690754719/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/05/la-multiplicacion-de-gauss.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6016017440690754719'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6016017440690754719'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/05/la-multiplicacion-de-gauss.html' title='La multiplicación de Gauss'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-4890628842060459814</id><published>2011-04-29T21:05:00.001+02:00</published><updated>2011-05-03T16:46:53.635+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algoritmos'/><category scheme='http://www.blogger.com/atom/ns#' term='lenguajes de programación'/><category scheme='http://www.blogger.com/atom/ns#' term='semántica formal'/><title type='text'>Transformación CPS</title><content type='html'>Hace algún tiempo hablamos de las &lt;a href="http://elmanantialdebits.blogspot.com/2010/02/continuaciones.html"&gt;continuaciones&lt;/a&gt;. Además, dimos una &lt;a href="http://elmanantialdebits.blogspot.com/2010/10/semantica-operacional-de-continuaciones.html"&gt;semántica operacional&lt;/a&gt; para ellas. Ahora vamos a describir cómo se transforma un programa para que use continuaciones en todas sus llamadas a función. Esto es el estilo de paso de continuaciones (&lt;a href="http://en.wikipedia.org/wiki/Continuation_passing_style"&gt;CPS&lt;/a&gt;) que permite eliminar la necesidad de usar una pila de llamadas. Es decir, la &lt;a href="http://elmanantialdebits.blogspot.com/2010/04/la-cadena-dinamica-y-la-cadena-estatica.html"&gt;cadena dinámica&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;El estilo de paso de continuaciones (CPS)&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Para empezar, veamos cómo es eso del CPS. Supongamos la siguiente expresión.&lt;br /&gt;[$$ f(g(a)) $$]&lt;br /&gt;Lo primero que calculamos es el valor de [$a$]. Luego, el valor de [$g(a)$] y, finalmente, el valor de [$f(g(a))$]. El estilo CPS añade un argumento adicional a cada función que es la continuación, a la que le pasaremos el resultado cuando la función termine.&lt;br /&gt;&lt;br /&gt;¿A dónde pasábamos el resultado de [$g(a)$]? A [$f$]. Así que, al hacer [$g$] CPS, la expresión de arriba queda&lt;br /&gt;[$$ g(f, a) $$]&lt;br /&gt;y se leería algo así como "calcula [$g(a)$] y pásale el resultado a [$f$]. El problema es que también tenemos que hacer CPS a [$f$] por lo que ahora [$f$] no toma un argumento, toma dos: la continuación y su argumento propiamente dicho. La solución es añadir una función anónima. La expresión de arriba con tanto [$g$] como [$f$] puestas en CPS sería así:&lt;br /&gt;[$$g(\lambda x.f(k,x), a)$$]&lt;br /&gt;El detalle es que [$k$] es la continuación de la expresión, que no sabemos cuál es porque no he dicho qué vamos a hacer después de calcular [$f(g(a))$]. Para destacar claramente que [$k$] es la continuación, que [$f(g(a))$] es la expresión original y que [$g(\lambda x.f(k,x), a)$] es la expresión transformada a CPS, vamos a usar la siguiente notación:&lt;br /&gt;[$$ T\ [\ f(g(a))\mid k\ ]\ = g(\lambda x.f(k,x), a) $$]&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;La transformación de Plotkin&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Bastará conocer las reglas de la transformación [$ T\ [\ ]$] para poder realizarla. Esto es a lo que se dedicó &lt;a href="http://en.wikipedia.org/wiki/Gordon_Plotkin"&gt;Plotkin&lt;/a&gt; en 1975 en el &lt;a href="http://homepages.inf.ed.ac.uk/gdp/publications/cbn_cbv_lambda.pdf"&gt;artículo&lt;/a&gt; "Call-by-name, call-by-value and the [$\lambda$]-calculus", aunque ha llovido mucho y la versión que presento aquí es bastante distinta a la original.&lt;br /&gt;&lt;br /&gt;Lo primero que necesitamos es definir el lenguaje que vamos a transformar. Vamos a usar una variante del lambda cálculo sin &lt;a href="http://www.blogger.com/"&gt;&lt;span id="goog_348434737"&gt;&lt;/span&gt;currificar&lt;span id="goog_348434738"&gt;&lt;/span&gt;&lt;/a&gt;. Es muy sencilla: un valor es o bien una variable o bien una función anónima.&lt;br /&gt;[$$ v::= x \mid \lambda (x_1,...,x_n).e $$]&lt;br /&gt;Una expresión es o bien un valor o bien una aplicación (llamo [$s$] a las aplicaciones).&lt;br /&gt;[$$ e::= v \mid s $$]&lt;br /&gt;También llamaremos, [$k$] a una expresión. Una aplicación no es más que una llamada a función.&lt;br /&gt;[$$ s::= e_0 (e_1,...,e_n) $$]&lt;br /&gt;Para transformar un programa escrito con esta sintaxis hemos de dar la transformación para cada una de estas construcciones sintácticas. Si lo que tengo un valor, ya está calculado, sólo he de pasarlo a la continuación. ¡Pero ojo! Si es una función he de transformarla antes en CPS. De esto se va a encargar la transformación auxiliar [$ M[\ ]$].&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Regla P-TV: [$ T\ [\ v\mid k\ ]= k(M[\ v\ ])$]&lt;/li&gt;&lt;/ul&gt;La transformación auxiliar es bien sencilla: si no es una función no hace nada, si es una función le añade el argumento de la continuación y transforma su cuerpo.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Regla P-MX: &amp;nbsp;[$ M\ [\ x\ ]=x $]&lt;/li&gt;&lt;li&gt;Regla P-ML: [$ M\ [\ \lambda(x_1,...,x_n).e\ ]=\lambda(x,x_1,...,x_n).T[\ e\mid x\ ] $]&lt;/li&gt;&lt;/ul&gt;Finalmente, si lo que tenemos es una aplicación, vamos calculando su operador y argumentos hasta que, al final, podamos llamar a la función.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Regla P-TS: [$ T\ [\ e_0(e_1,...,e_n) \mid k\ ]=T[\ e_0 \mid \lambda x_0.T[\ e_1 \mid \lambda x_1.\ ...T[\ e_n \mid \lambda x_n. x_0(k, x_1,...,x_n)\ ]\ ...\ ]\ ] $]&lt;/li&gt;&lt;/ul&gt;Va a ser muy habitual encontrarnos con transformaciones anidadas del tipo [$...T[\ e\mid\lambda x.T[...$] ya que representan una secuencia de operaciones. El resultado de [$e$] se pasa a la continuación que empieza por [$\lambda x...$] lo que hace guardar el resultado de [$e$] en [$x$] y proseguir con la ejecución de la secuencia. Para facilitar la comprensión de una expresión en CPS vamos a poner como subíndice de una variable la expresión cuyo valor guarda.&lt;br /&gt;&lt;br /&gt;Bien, ahora que tenemos las cuatro reglas de Plotkin vamos a probar a ver cómo transforma a [$f(g(a))$]. Vamos a hacerlo paso a paso.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Inicial: [$T[\ f(g(a)) \mid k\ ]$]&lt;/li&gt;&lt;li&gt;Regla P-TS: [$ T[\ f \mid \lambda x_f.T[\ g(a) \mid \lambda x_{g(a)}. x_f(k, x_{g(a)})\ ]\ ] $]&lt;/li&gt;&lt;li&gt;Regla P-TV: [$ (\lambda x_f.T[\ g(a) \mid \lambda x_{g(a)}. x_f(k, x_{g(a)})\ ]\ )(M[\ f\ ]) $]&lt;/li&gt;&lt;li&gt;Regla P-MV: [$ (\lambda x_f.T[\ g(a) \mid \lambda x_{g(a)} &amp;nbsp;. x_f(k, x_{g(a)})\ ]\ )(f) $] &amp;nbsp;&lt;/li&gt;&lt;li&gt;Regla P-TS: [$ (\lambda x_f.T[g \mid \lambda x_g.T[\ a \mid \lambda x_a. x_g( \lambda x_1. x_f(k, x_{g(a)}) , x_a)\ ]\ ]\ )(f) $] &amp;nbsp;&lt;/li&gt;&lt;li&gt;Regla P-TV: [$ (\lambda x_f. (\lambda x_g.T[\ a \mid \lambda x_a. x_g( \lambda x_{g(a)}. x_f(k, x_{g(a)}) , x_a)\ ]\ )(M[\ g\ ]) )(f) $]&lt;/li&gt;&lt;li&gt;Regla P-MV: [$ (\lambda x_f. (\lambda x_g.T[\ a \mid \lambda x_a. x_g( \lambda x_{g(a)}. x_f(k, x_{g(a)}) , x_a)\ ]\ )(g) )(f) $]&lt;/li&gt;&lt;li&gt;Regla P-TV: [$ (\lambda x_f. (\lambda x_g.&amp;nbsp; (\lambda x_a. x_g( \lambda x_{g(a)}. x_f(k, x_{g(a)}) , x_a) )(M[\ a\ ]\ ) )(g) )(f) $]&lt;/li&gt;&lt;li&gt;Regla P-MV: [$ (\lambda x_f. (\lambda x_g.&amp;nbsp; (\lambda x_a. x_g( \lambda x_{g(a)}. x_f(k, x_{g(a)}) , x_a) )(a) )(g) )(f) $]&lt;/li&gt;&lt;/ol&gt;&amp;nbsp;El resultado de esta expresión es sorprendentemente complejo. Además, parece que podríamos usar varias veces &lt;a href="http://elmanantialdebits.blogspot.com/2010/05/las-reglas-del-lambda-calculo.html"&gt;la regla beta&lt;/a&gt; para reducir un poco más la expresión.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Del anterior: [$ (\lambda x_f. (\lambda x_g.&amp;nbsp; (\lambda x_a. x_g( \lambda x_{g(a)}. x_f(k, x_{g(a)}) , x_a) )(a) )(g) )(f) $]  &lt;/li&gt;&lt;li&gt;Regla beta: [$ (\lambda x_g.&amp;nbsp; (\lambda x_a. x_g( \lambda x_{g(a)}. f(k, x_{g(a)}) , x_a) )(a) )(g) $]&lt;/li&gt;&lt;li&gt;Regla beta: [$ (\lambda x_a. g( \lambda x_{g(a)}. f(k, x_{g(a)}) , x_a) )(a) $]&lt;/li&gt;&lt;li&gt;Regla beta: [$ g( \lambda x_{g(a)}. f(k, x_{g(a)}) , a) $]&lt;/li&gt;&lt;/ol&gt;Esto sí se parece a lo que teníamos inicialmente, el problema es que no podemos realizar reglas beta ya que estamos transformando código y ¿cómo sabemos qué lambdas son del código y qué lambdas son las introducidas por la transformación?&lt;br /&gt;&lt;br /&gt;¡Ah!... Se me ocurre una idea. Podríamos etiquetarlas...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="color: #666666;"&gt;Nota: ¿Por qué no podemos realizar reglas beta en el código? Imaginemos la siguiente expresión [$(\lambda x.3)(f(x))$]. Si [$f(x)$] tiene efectos secundarios, al realizar la regla beta obtendríamos [$3$] y habríamos perdido los efectos secundarios.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;&amp;nbsp;La tranformación de alto nivel de Appel&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Esta fue la idea que se le ocurrió a &lt;a href="http://en.wikipedia.org/wiki/Andrew_Appel"&gt;Appel&lt;/a&gt; en 1992 para su libro "&lt;a href="http://www.amazon.com/Compiling-Continuations-Andrew-W-Appel/dp/0521416957"&gt;Compiling with Continuations&lt;/a&gt;", pero no es tan sencilla. En primer lugar estaríamos tentados a etiquetar (con una rayita encima) las lambda que fueran introducidas por la transformación a CPS. Empecemos por la regla que las introduce: la P-TS que renombraremos a A-TS.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Regla A-TS: [$ T\ [\ e_0(e_1,...,e_n) \mid k\ ]=$][$T[\ e_0 \mid \bar\lambda x_0.T[\ e_1 \mid \bar\lambda x_1.\ ...T[\ e_n \mid \bar\lambda x_n. x_0(k, x_1,...,x_n)\ ]\ ...\ ]\ ] $]&lt;/li&gt;&lt;/ul&gt;El problema es que las [$\bar\lambda$] no son código, son funciones sobre el código (de ahí lo de alto nivel). Si dejáramos las cosas así obtendríamos&lt;br /&gt;[$$ T[\ f(a)(b)\ ]=f(\bar\lambda x_{f(a)}.x_{f(a)}(k,b), a) $$]&lt;br /&gt;Y eso no es código. No es código porque contiene un [$\bar\lambda$] que es una función sobre el código. No está en la sintaxis que pusimos al inicio.&lt;br /&gt;&lt;br /&gt;La solución se obtiene forzando que las continuaciones se especifiquen siempre de forma indirecta, como una función sobre el código. En ese aspecto, cambiamos la regla P-ML de la siguiente forma (la nueva regla es la A-ML):&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Regla P-ML: [$ M\ [\ \lambda(x_1,...,x_n).e\ ]=\lambda(x,x_1,...,x_n).T[\ e\mid x\ ] $] &amp;nbsp;&lt;/li&gt;&lt;li&gt;Regla A-ML: [$ M\ [\ \lambda(x_1,...,x_n).e\ ]=\lambda(x,x_1,...,x_n).T[\ e\mid \bar\lambda x_0.x x_0\ ] $] &amp;nbsp;&lt;/li&gt;&lt;/ul&gt;El truco está en que [$\bar\lambda x_0.x x_0$] convierte el código [$x$] en una función que toma código [$x_0$] y devuelve código [$x x_0$]. Como [$x$] va a ser la continuación, el efecto es pasarle [$x_0$] a la continuación. Justo lo que teníamos antes pero, esta vez, el [$\bar\lambda$] significa que estoy trabajando con funciones sobre código y no sobre código. Podré usar la regla beta para simplificarlas. Lo que buscábamos a la hora de etiquetar.&lt;br /&gt;&lt;br /&gt;También hay que trastear la regla A-TS porque [$k$] no es código.&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Regla P-TS: [$ T\ [\ e_0(e_1,...,e_n) \mid k\ ]= $][$ T[\ e_0 \mid \lambda x_0.T[\ e_1 \mid \lambda x_1.\ ...T[\ e_n \mid \lambda x_n. x_0(k, x_1,...,x_n)\ ]\ ...\ ]\ ] $]&amp;nbsp;&lt;/li&gt;&lt;li&gt;&amp;nbsp;Regla A-TS antigua (etiqueto lambdas): [$ T\ [\ e_0(e_1,...,e_n) \mid k\ ]= $][$ T[\ e_0 \mid \bar\lambda x_0.T[\ e_1 \mid \bar\lambda x_1.\ ...T[\ e_n \mid  \bar \lambda x_n. x_0(k, x_1,...,x_n)\ ]\ ...\ ]\ ] $]&amp;nbsp;&lt;/li&gt;&lt;li&gt;Regla A-TS nueva (arreglo [$k$]): [$ T\ [\ e_0(e_1,...,e_n) \mid k\ ]= $][$ T[\ e_0 \mid \bar\lambda x_0.T[\ e_1 \mid \bar\lambda x_1.\ ...T[\ e_n \mid  \bar \lambda x_n. x_0(\lambda x.k x, x_1,...,x_n)\ ]\ ...\ ]\ ] $]&lt;/li&gt;&lt;/ul&gt;El truco de [$\lambda x.kx$] es que [$k$] es una función de código que tomará el código [$x$] y generará otro código que permanece dentro del cuerpo de [$\lambda x$]. El resultado es, por tanto, código. Para dejar claro qué variables son de código y qué variables son funciones sobre el código, también etiquetaremos estas últimas que incluirán ahora todas las continuaciones también.&lt;br /&gt;&lt;br /&gt;Entonces, las reglas de transformación de alto nivel definitivas son las siguientes:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Regla A-MX: &amp;nbsp;[$ M\ [\ x\ ]=x $]&lt;/li&gt;&lt;li&gt;Regla A-ML: [$ M\ [\ \lambda(x_1,...,x_n).e\ ]=\lambda(x,x_1,...,x_n).T[\ e\mid &amp;nbsp; \bar\lambda x_0.x x_0 &amp;nbsp;\ ] $]&lt;/li&gt;&lt;li&gt;Regla A-TV: [$ T\ [\ v\mid \bar k\ ]= k(M[\ v\ ])$]&lt;/li&gt;&lt;li&gt;Regla A-TS: [$ T\ [\ e_0(e_1,...,e_n) \mid \bar k\ ]=$][$T[\ e_0 \mid \bar\lambda x_0.T[\ e_1 \mid \bar\lambda x_1.\ ...T[\ e_n \mid \bar\lambda x_n. x_0(\lambda x.\bar k x, x_1,...,x_n)\ ]\ ...\ ]\ ] $]&lt;/li&gt;&lt;li&gt;&amp;nbsp;Regla beta: [$ (\bar\lambda (x_1,...x_n). e) (v_1,...,v_n) = [x_1 \rightarrow v_1,...,&amp;nbsp; x_n \rightarrow v_n &amp;nbsp;]e $]&lt;/li&gt;&lt;/ul&gt;Mejoran mucho el resultado de la transformación a CPS. El único inconveniente es que debemos trabajar con funciones sobre código (de alto nivel). Así que, si [$k$] sin etiquetar es código, no puedo escribir&lt;br /&gt;[$$ T[\ f(a)\mid k\ ]$$]&lt;br /&gt;Tengo que escribir&lt;br /&gt;[$$ T[\ f(a)\mid \bar\lambda x.k x\ ]$$] &lt;br /&gt;y el resultado de esto no es todo lo perfecto que quisiéramos:&lt;br /&gt;[$$ f( \lambda x.k x, a) $$]&lt;br /&gt;Se me ocurre otra idea... ¿Y no podemos mezclar las reglas de Plotkin y de Appel para usar código o funciones sobre código cuando queramos?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;La tranformación CPS híbrida&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Separemos entonces [$T\ [\ ]$] en dos: una sin etiqueta y otra con etiqueta [$\bar T\ [\ ]$]. La versión sin etiqueta requiere que la continuación sea código [$T\ [\ e\mid k\ ]$] y la etiquetada requiere que sea una función sobre código [$\bar T\ [\ e\mid \bar k\ ]$]. La mezcla es sencilla.&amp;nbsp; &lt;br /&gt;&lt;ul&gt;&lt;li&gt;Regla H-MX: &amp;nbsp;[$ M\ [\ x\ ]=x $]&lt;/li&gt;&lt;li&gt;Regla H-ML: [$ M\ [\ \lambda(x_1,...,x_n).e\ ]=\lambda(x,x_1,...,x_n).T[\ e\mid x \ ] $]&lt;/li&gt;&lt;li&gt;Regla H-TV: [$ T\ [\ v\mid k\ ]= k(M[\ v\ ])$]&lt;/li&gt;&lt;li&gt;Regla H-TS: [$ T\ [\ e_0(e_1,...,e_n) \mid k\ ]=$][$\bar T[\ e_0 \mid \bar\lambda x_0. \bar  T[\ e_1 \mid \bar\lambda x_1.\ ... \bar  T[\ e_n \mid \bar\lambda x_n. x_0(k, x_1,...,x_n)\ ]\ ...\ ]\ ] $] &amp;nbsp;&lt;/li&gt;&lt;li&gt;Regla H-FV: [$ \bar T\ [\ v\mid \bar k\ ]= \bar k(M[\ v\ ])$]&lt;/li&gt;&lt;li&gt;Regla H-FS: [$ \bar T\ [\ e_0(e_1,...,e_n) \mid \bar k\ ]=$] [$\bar T[\ e_0 \mid \bar\lambda x_0. \bar T[\ e_1 \mid \bar\lambda x_1.\ ... \bar T[\ e_n \mid \bar\lambda x_n. x_0(\lambda x.\bar k x, x_1,...,x_n)\ ]\ ...\ ]\ ] $]&lt;/li&gt;&lt;li&gt;Regla beta: [$ (\bar\lambda (x_1,...x_n). e) (v_1,...,v_n) = [x_1 \rightarrow v_1,...,&amp;nbsp; x_n \rightarrow v_n &amp;nbsp;]e $] &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Con estas reglas sí que conseguimos el objetivo deseado.&lt;br /&gt;[$$ T\ [\ f(a)\mid k\ ]\ = f(k,a)$$] &lt;br /&gt;[$$ T\ [\ f(g(a))\mid k\ ]\ = g(\lambda x.f(k,x), a) $$]&lt;br /&gt;El único problemilla que tenemos es que trabajamos como en dos fases. En la primera fase quitamos las [$T$] (y [$\bar T$]) de en medio y en la segunda fase quitamos las [$\bar \lambda$] con la regla beta. Es posible &lt;a href="http://www.google.es/url?sa=t&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CBgQFjAA&amp;amp;url=http%3A%2F%2Fciteseerx.ist.psu.edu%2Fviewdoc%2Fdownload%3Fdoi%3D10.1.1.94.1279%26rep%3Drep1%26type%3Dpdf&amp;amp;ei=0AK7TcXDLcqEhQfW0bC5BQ&amp;amp;usg=AFQjCNGgIK6_T7k6t4DpYUTH72DjxBxQag"&gt;hacerlo todo a la vez&lt;/a&gt;, pero aumenta lo suficiente la complejidad como para no explicarlo aquí (se basa en separar las [$e$] en [$v$] y en [$s$] y tratar cada caso con una regla distinta, específica).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Transformación CPS para lenguajes reales&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Para finalizar vamos a apuntar brevemente cómo son las reglas de transformación CPS para un lenguaje de programación real, con asignación, selección, secuencia y demás primitivas.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;AsignaciónT: [$ T\ [\ \mathrm{set}\ x\ e \mid k\ ]=\bar T[ e \mid \bar\lambda x_0. k (&amp;nbsp; \mathrm{set}\ &amp;nbsp; x\ e)\ ] $]&lt;/li&gt;&lt;li&gt;AsignaciónF:&amp;nbsp;[$ \bar T\ [\  \mathrm{set}\ &amp;nbsp;x\ e \mid  \bar  k\ ]=\bar T[ e \mid \bar\lambda x_0.  \bar  k (&amp;nbsp; \mathrm{set}\ &amp;nbsp; x\ e)\ ] $]&lt;/li&gt;&lt;li&gt;SelecciónT: [$ T\ [\ \mathrm{if}\ e_1\ e_2\ e_3 \mid k\ ]=\bar T[\ e_1 \mid \bar\lambda x_1. (&amp;nbsp; \mathrm{if}\ x_1\ T[\ e_2 \mid k\ ]\ T[\ e_3 \mid k\ ]\ ] $]&lt;/li&gt;&lt;li&gt;SelecciónF: [$ \bar T\ [\ &amp;nbsp; \mathrm{if}\ e_1\ e_2\ e_3 \mid  \bar  k\ ]=\bar T[\ e_1 \mid \bar\lambda x_1. (&amp;nbsp; \mathrm{if}\ x_1\  \bar  T[\ e_2 \mid  \bar  k\ ]\  \bar  T[\ e_3 \mid  \bar  k\ ]\ ] $]&lt;/li&gt;&lt;li&gt;SecuenciaT: [$ T\ [\ e_1 ; e_2 \mid k \ ]=  \bar T[\ e_1 \mid \bar\lambda x.T[\ e_2 \mid k\ ]\ ] $]&lt;/li&gt;&lt;li&gt;SecuenciaF: [$ \bar T\ [\ e_1 ; e_2 \mid  \bar k \ ]=  \bar T[\ e_1 \mid \bar\lambda x. \bar T[\ e_2 \mid  \bar k\ ]\ ] $]&lt;/li&gt;&lt;/ul&gt;La selección duplica el código que hay en la continuación porque lo usa en dos sitios. Esto puede dar lugar a un código final más grande de lo deseable. La solución es postergar a tiempo de ejecución el paso de la continuación de la siguiente forma:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;SelecciónT2: [$ T\ [\ \mathrm{if}\ e_1\ e_2\ e_3 \mid k\ ]=(\lambda x. \bar T[\ e_1 \mid \bar\lambda x_1. (&amp;nbsp; \mathrm{if}\ x_1\ T[\ e_2 \mid k\ ]\ T[\ e_3 \mid x\ ]\ ])(k) $] &amp;nbsp;&amp;nbsp;&lt;/li&gt;&lt;li&gt;SelecciónF2: [$ \bar T\ [\ &amp;nbsp; \mathrm{if}\ e_1\ e_2\ e_3 \mid  \bar  k\ ]=(\lambda x. \bar T[\ e_1 \mid \bar\lambda x_1. (&amp;nbsp; \mathrm{if}\ x_1\  \bar  T[\ e_2 \mid  \bar  x\ ]\  \bar  T[\ e_3 \mid  \bar  k\ ]\ ])(\lambda x_0.\bar k x_0) $] &amp;nbsp;&lt;/li&gt;&lt;/ul&gt;La clásica función call/cc se implementa así.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;CallCCT: [$ T\ [\ \mathrm{calcc}\ | k\ ] = k (\lambda(x_0,x_1).x_1(x_0,\lambda(x_2,x_3).x_0(x_3))) $]&lt;/li&gt;&lt;li&gt;CallCCF: [$ \bar T\ [\  \mathrm{calcc} \ |  \bar  k\ ] =&amp;nbsp; \bar  k (\lambda(x_0,x_1).x_1(x_0,\lambda(x_2,x_3).x_0(x_3))) $]&lt;/li&gt;&lt;/ul&gt;Los let se pueden implementar como lambdas aplicados inmediatamente, pero los &lt;a href="http://neilmitchell.blogspot.com/2007/03/let-vs-letrec.html"&gt;letrec&lt;/a&gt;, no. Asumimos que los letrec sólo pueden vincular valores. Entonces:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;LetRecT: [$ T\ [\ \mathrm{letrec}\ x_1=v_1,...,x_n=v_n\ \mathrm{in}\ e \mid k\ ]=$][$\mathrm{letrec}\ x_1=M[\ v_1\ ],...,x_n=M[\ v_n\ ]\ \mathrm{in}\ T[\ e \mid k\ ] $]&lt;/li&gt;&lt;li&gt;LetRecF: [$ \bar T\ [\ \mathrm{letrec}\ x_1=v_1,...,x_n=v_n\ \mathrm{in}\ e \mid  \bar  k\ ]=$][$\mathrm{letrec}\ x_1=M[\ v_1\ ],...,x_n=M[\ v_n\ ]\ \mathrm{in}\  \bar  T[\ e \mid  \bar  k\ ] $]&lt;/li&gt;&lt;/ul&gt;&lt;span style="color: red;"&gt;&lt;b&gt;Referencias&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://matt.might.net/articles/cps-conversion/"&gt;Matt Might - How to compile with continuations&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.iro.umontreal.ca/~boucherd/mslug/meetings/20041020/90-min-scc/90-min-scc.pdf"&gt;Mark Feeley - The 90 minute Scheme to C compiler&amp;nbsp;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-4890628842060459814?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/4890628842060459814/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/04/transformacion-cps.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/4890628842060459814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/4890628842060459814'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/04/transformacion-cps.html' title='Transformación CPS'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-5978039494941535788</id><published>2011-04-27T19:40:00.009+02:00</published><updated>2011-04-29T10:44:07.534+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Máquinas virtuales'/><category scheme='http://www.blogger.com/atom/ns#' term='ensamblador'/><category scheme='http://www.blogger.com/atom/ns#' term='semántica formal'/><title type='text'>Modelos de memoria compartida</title><content type='html'>&lt;b&gt;&lt;span style="color: red;"&gt;Orden de programa&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Un programa se compone de instrucciones.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;1 x=A //Lee el valor de A&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;2 B=2 //Escribe un valor en B&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;3 y=B //Lee el valor de B&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Usaré las letras mayúsculas (A,B,C) para las localizaciones de memoria y las minúsculas (a,b,c) para registros o valores que no estén en memoria. Como nos interesa el modelo de memoria, ignoraremos las operaciones que no trabajen con memoria. Para mayor facilidad usaremos números para cada instrucción.&lt;br /&gt;&lt;br /&gt;Cuando se ejecuta un programa las instrucciones que se van ejecutando conforman una secuencia que se denomina traza. Se llama orden de programa a la relación de orden estricto que encadena las instrucciones según se ejecutan en una traza. Si escribimos esta relación como [$ \rightarrow_p $] entonces, el programa de arriba tiene la siguiente traza&lt;br /&gt;&lt;br /&gt;[$$ 1 \rightarrow_p 2 \rightarrow_p 3 $$]&lt;br /&gt;&lt;br /&gt;Nada extraño. Esta relación es un &lt;a href="http://elmanantialdebits.blogspot.com/2010/07/relaciones-binarias.html"&gt;orden estricto y, en principio, total&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Modelo secuencialmente consistente (SC)&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Cuando tenemos varios procesadores, cada uno de ellos ejecutando una hebra distinta, ¿cómo se reparten las instrucciones? ¿Y qué instrucciones se ejecutan antes que otras? Un modelo de memoria compartida responde a estas preguntas.&lt;br /&gt;&lt;br /&gt;El modelo más simple es el &lt;i&gt;secuencialmente consistente&lt;/i&gt; (SC) de &lt;a href="http://en.wikipedia.org/wiki/Leslie_Lamport"&gt;Lamport&lt;/a&gt;. En este modelo las instrucciones de todos los procesadores se intercalan y el orden resultante de las mismas ha de ser un orden total que llamaremos de &lt;i&gt;ocurrencia&lt;/i&gt; [$ \rightarrow_o $].&lt;br /&gt;&lt;br /&gt;Si no pusiéramos más condiciones, este orden podría ser cualquiera, incluso sin respetar el orden de programa.&lt;br /&gt;&lt;br /&gt;Por ejemplo, este programa con dos hebras&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;INICIALMENTE: A=B=0&lt;br /&gt;HEBRA 1    &amp;nbsp; HEBRA 2&lt;br /&gt;1 x=A      &amp;nbsp; &amp;nbsp; 11 y=B&lt;br /&gt;2 B=1      &amp;nbsp; &amp;nbsp; 12 A=1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Tiene el siguiente orden de programa&lt;br /&gt;&lt;br /&gt;[$$ 1 \rightarrow_p 2 $$]&lt;br /&gt;[$$ 11 \rightarrow_p 12 $$]&lt;br /&gt;&lt;br /&gt;Sin condiciones adicionales, el orden de ocurrencia podría ser, por ejemplo&lt;br /&gt;&lt;br /&gt;[$$ 2 \rightarrow_o 12 \rightarrow_o 1 \rightarrow_o 11 $$]&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="color: #666666;"&gt;Nota: Tanto el orden [$ \rightarrow_p $] como el orden [$ \rightarrow_o $] son transitivos por lo que con el ejemplo de arriba también tendríamos [$ 2&amp;nbsp;\rightarrow_o 1, 2 \rightarrow_o 11, 12&amp;nbsp;\rightarrow_o 11 $].&amp;nbsp;Es usual no listar estas relaciones que se pueden derivar fácilmente de la primera.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Este orden daría como resultado x=y=1 lo cual es bastante contraintuitivo. El modelo SC tiene la siguiente restricción: si [$N$] y [$M$] son dos instrucciones y [$ N \rightarrow_p M $] entonces debe darse que [$ N \rightarrow_o M $]. Esta condición se expresa de la siguiente manera.&lt;br /&gt;&lt;br /&gt;[$$ \frac{N \rightarrow_p M}{N \rightarrow_o M} $$]&lt;br /&gt;&lt;br /&gt;Esto quiere decir que si en una hebra se ejecuta una instrucción antes que otra por el orden de programa (por ejemplo, la 11 antes de la 12) entonces ese mismo orden aparece en el orden de ocurrencia. Como en el ejemplo anterior teníamos que 12 ocurría antes que 11, excluimos este posible orden del modelo SC.&lt;br /&gt;&lt;br /&gt;[$ 2 \rightarrow_o 12 \rightarrow_o 1 \rightarrow_o 11$] no es SC porque [$2 \rightarrow_o 1$] pero [$1 \rightarrow_p 2$]&lt;br /&gt;[$ 11 \rightarrow_o 1 \rightarrow_o 2 \rightarrow_o 12 $] sí es SC y el resultado es un intuitivo x=y=0&lt;br /&gt;[$ 1 \rightarrow_o 2 \rightarrow_o 11 \rightarrow_o 12 $] sí es SC y el resultado es otro intuitivo x=0, y=1&lt;br /&gt;&lt;br /&gt;El dibujo típico del modelo secuencialmente consistente es una memoria compartida asignada únicamente a un procesador en cada momento.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-lU7dKf9Fs6o/TanZ-YaZaoI/AAAAAAAAAGU/00gs6-4ynhs/s1600/ModeloSC.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="198" src="http://3.bp.blogspot.com/-lU7dKf9Fs6o/TanZ-YaZaoI/AAAAAAAAAGU/00gs6-4ynhs/s320/ModeloSC.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;Optimizaciones en compiladores y procesadores&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Desafortunadamente las cosas no son tan sencillas. Generalmente el orden de programa es excesivamente restrictivo para realizar &lt;i&gt;optimizaciones&lt;/i&gt;. Una optimización típica es la siguiente.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;1 A=5&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;2 x=A&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;3 B=1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En el anterior programa, la instrucción 2 ha de esperar a que la instrucción 1 escriba el valor 5 en A. Un compilador o un procesador astuto &lt;i&gt;reordena el programa&lt;/i&gt; de la siguiente forma.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;11 A=5&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&lt;span style="color: #cc0000;"&gt;12 B=1&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&lt;span style="color: #cc0000;"&gt;13 x=A&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En este programa transformado, la instrucción 12 se ejecuta mientras la instrucción 11 se está terminando. Esto evita que tengamos que esperar en la instrucción 13 tanto como hacíamos en la instrucción 2.&lt;br /&gt;&lt;br /&gt;El problema es que el programador ha escrito las instrucciones 1,2,3 y no las 11,12,13. ¿Qué pasa si ejecutamos esto con otra hebra?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;HEBRA 1 &amp;nbsp;      HEBRA 2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;1 A=5        &amp;nbsp; &amp;nbsp; 21 if(B=1)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;2 x=A        &amp;nbsp; &amp;nbsp; 22 &amp;nbsp;   A=7&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;3 B=1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Pensando en SC de ninguna manera podría ocurrir que x=7 ya que para cuando B=1, x ya tiene el valor 5 y por mucho que modifiquemos A=7, x ya no va a cambiar. Esto no es así si el procesador o el compilador reordena el programa de la hebra 1 sin que lo sepamos.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;HEBRA 1 &amp;nbsp;      HEBRA 2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;11 A=5       &amp;nbsp; &amp;nbsp;21 if(B=1)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;12 B=1       &amp;nbsp; &amp;nbsp;22 &amp;nbsp;   A=7&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;13 x=A&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Aunque el programador ha escrito 1,2,3, el compilador o el procesador lo reordena a 11,12,13 para optimizar la espera de la instrucción 2 tras la 1. Ahora bien, ¡esto ahora permite que x=7! El orden de ocurrencia para este bug sería&lt;br /&gt;&lt;br /&gt;[$$ 11 \rightarrow_o 12 \rightarrow_o 21 \rightarrow_o 22 \rightarrow_o 13 $$]&lt;br /&gt;&lt;br /&gt;Si el pobre programador intenta razonar sobre el orden del programa original 1,2,3 lo que vería sería&lt;br /&gt;&lt;br /&gt;[$$ 1 \rightarrow_o 3 \rightarrow_o 21 \rightarrow_o 22 \rightarrow_o 2 $$]&lt;br /&gt;&lt;br /&gt;que no es SC porque la instrucción 3 se ejecuta antes que la 2.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;Relajando el modelo SC&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Por esta razón el modelo SC no es útil: no permite al compilador o al procesador optimizar los programas sin dejar al programador con un difícil bug a resolver. La solución es exponer al programador un modelo más débil que se denomina un &lt;i&gt;modelo relajado&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;¿Cómo vamos a relajar ese modelo? Hay varias formas.&lt;br /&gt;&lt;br /&gt;La primera es permitir reordenar las instrucciones de un programa y proporcionar al programador &lt;i&gt;herramientas&lt;/i&gt; para decirle al compilador y al procesador cuándo no se pueden reordenar. Una de estas herramientas es una instrucción llamada &lt;i&gt;barrera de memoria&lt;/i&gt; (memory fence) y lo único que significa es que es una barrera que las instrucciones no se la pueden saltar al ser reordenadas.&lt;br /&gt;&lt;br /&gt;Con una barrera, el programa anterior quedaría así&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;HEBRA 1      &amp;nbsp; HEBRA 2&lt;br /&gt;1 A=5        &amp;nbsp; &amp;nbsp; 21 if(B=1)&lt;br /&gt;2 x=A        &amp;nbsp; &amp;nbsp; 22   A=7&lt;br /&gt;3 FENCE&lt;br /&gt;4 B=1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Y ni el compilador ni el procesador podrían reordenar la instrucción 4 sobre la 3 o la 1 o la 2 bajo la 3. De esta manera, el programador se asegura de que leemos A antes de modificar B. Por otra parte, el compilador o el procesador son libres de realizar otras optimizaciones en otros sitios.&lt;br /&gt;&lt;br /&gt;¿Pero en qué sitios? ¿Podría reordenar la instrucción 2 sobre la 1? Realmente no, porque necesitamos conocer A en la instrucción 2 y eso depende de la instrucción 1. A esta relación se la llama una &lt;i&gt;dependencia&lt;/i&gt; y la escribiremos [$\rightarrow_d$]. Básicamente indica que un valor no se puede usar antes de que haya sido calculado. En un modelo de memoria relajado al menos se debe conservar la dependencia. Es decir,&lt;br /&gt;&lt;br /&gt;[$$\frac{N \rightarrow_d M}{N \rightarrow_o M}$$]&lt;br /&gt;&lt;br /&gt;Además, las barreras de memorias ordenan lo que ocurre antes y después de ellas.&lt;br /&gt;&lt;br /&gt;[$$\frac{N \rightarrow_p M, &amp;nbsp;N\ es\ FENCE}{N \rightarrow_o M},\ \ \frac{N \rightarrow_p M, &amp;nbsp;M\ es\ FENCE}{N \rightarrow_o M}$$]&lt;br /&gt;&lt;br /&gt;Entonces, en el programa anterior teníamos.&lt;br /&gt;&lt;br /&gt;[$$1\rightarrow_p 2\rightarrow_p 3\rightarrow_p 4,11\rightarrow_p 12$$]&lt;br /&gt;[$$1\rightarrow_d 2,11\rightarrow_d 12$$]&lt;br /&gt;[$$3\ es\ FENCE$$]&lt;br /&gt;&lt;br /&gt;Por la dependencia debe cumplirse que&lt;br /&gt;&lt;br /&gt;[$$1\rightarrow_o 2,11\rightarrow_o 12$$]&lt;br /&gt;&lt;br /&gt;y por barrera debe cumplirse que&lt;br /&gt;&lt;br /&gt;[$$1\rightarrow_o 3,2\rightarrow_o 3,3\rightarrow_o 4$$]&lt;br /&gt;&lt;br /&gt;Entonces, está claro que&lt;br /&gt;&lt;br /&gt;[$1\rightarrow_o 11\rightarrow_o 2\rightarrow_o 12\rightarrow_o 3\rightarrow_o 4$] sí cumple con el modelo relajado&lt;br /&gt;[$1\rightarrow_o 11\rightarrow_o 2\rightarrow_o 12\rightarrow_o 4\rightarrow_o 3$] no cumple con el modelo relajado porque [$4\rightarrow_o 3$]&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #666666;"&gt;&lt;span style="font-size: x-small;"&gt;Nota: La instrucción 12 no se ejecuta, pero de ejecutarse lo haría en la posición arriba puesta.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #666666;"&gt;&lt;span style="font-size: x-small;"&gt;Nota: Sabemos que si [$4\rightarrow_o 3$] entonces no se da [$3\rightarrow_o 4$] porque estamos tratando con órdenes.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;Otras barreras, otros modelos, otras instrucciones&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Algunos compiladores y procesadores se restringen a reordenar instrucciones que son de cierto tipo. Los más usuales son&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Reordena una escritura seguida de otra escritura (WW)&lt;/li&gt;&lt;li&gt;Reordena una lectura seguida de una escritura (RW)&lt;/li&gt;&lt;li&gt;Reordena una escritura seguida de una lectura (WR)&lt;/li&gt;&lt;li&gt;Reordena una lectura seguida de otra lectura (RR)&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;Eso permite además tener &lt;i&gt;barreras de memoria selectivas&lt;/i&gt; que&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Impida reordenar escrituras anteriores a la barrera con escrituras posteriores (WW)&lt;/li&gt;&lt;li&gt;Impida reordenar lecturas anteriores a la barrera con escrituras posteriores (RW)&lt;/li&gt;&lt;li&gt;Impida reordenar escrituras anteriores a la barrera con lecturas posteriores (WR)&lt;/li&gt;&lt;li&gt;Impida reordenar lecturas anteriores a la barrera con lecturas posteriores (RR)&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;Esto lleva permitirle al compilador y al procesador más optimizaciones. Existen más métodos de restringir la reordenación como instrucciones atómicas, sincronizaciones, bloqueos, etc. Eso sí, empieza a crearnos un zoológico de modelos de memoria que, sin embargo, se dan en la vida real. Por ejemplo,&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;Procesador o&lt;/span&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;Modelo de memoria&amp;nbsp; Relaja WR &amp;nbsp;Relaja WW &amp;nbsp;Relaja RW &amp;nbsp;Relaja RR&lt;br /&gt;SC    &lt;br /&gt;IBM 360 &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; Sí  &lt;br /&gt;TSO &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; Sí  &lt;br /&gt;PC &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Sí  &lt;br /&gt;PSO &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &lt;br /&gt;WO &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí&lt;br /&gt;RCsc &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí&lt;br /&gt;RCpc &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí&lt;br /&gt;Alpha &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí&lt;br /&gt;RMO &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí&lt;br /&gt;PowerPC &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Sí&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Para más información &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.106.5742&amp;amp;rank=1"&gt;http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.106.5742&amp;amp;rank=1&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-5978039494941535788?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/5978039494941535788/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/04/modelos-de-memoria-compartida.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/5978039494941535788'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/5978039494941535788'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/04/modelos-de-memoria-compartida.html' title='Modelos de memoria compartida'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-lU7dKf9Fs6o/TanZ-YaZaoI/AAAAAAAAAGU/00gs6-4ynhs/s72-c/ModeloSC.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-4781366155740226891</id><published>2011-04-23T15:53:00.027+02:00</published><updated>2011-04-23T15:53:00.566+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algoritmos'/><category scheme='http://www.blogger.com/atom/ns#' term='lenguajes de programación'/><category scheme='http://www.blogger.com/atom/ns#' term='matemáticas'/><category scheme='http://www.blogger.com/atom/ns#' term='ensamblador'/><title type='text'>Divisiones y módulos enteros</title><content type='html'>Supongamos que queremos saber si un número es impar. ¿Bastaría este código?&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: cpp"&gt;bool impar(int n)&lt;br /&gt;{&lt;br /&gt; return (n%2) == 1;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Veamos. Introducimos el valor 5, hacemos la división por 2 y obtenemos el resto 1. Efectivamente, es impar. Ahora introduzcamos el valor -3, hacemos la división por 2 y obtenemos ¿qué resto? En mi implementación obtengo -1. Eso es un problema, pero ¿por qué sale -1? ¿No debería salir 1?&lt;br /&gt;&lt;br /&gt;El operador de módulo % está muy relacionado con la división entera. La división entera se define de la siguiente manera. Sean cuatro números enteros [$n, d, c$] y [$r$] que llamaremos dividendo, divisor, cociente y resto. Esos cuatro números cumplen la siguiente ecuación.&lt;br /&gt;&lt;br /&gt;[$$ n = dc + r $$]&lt;br /&gt;&lt;br /&gt;Si, además, imponemos la siguiente inecuación, el cociente y el resto son únicos para cada par de dividendo y divisor.&lt;br /&gt;&lt;br /&gt;[$$ 0\le r \lt \left| d \right| $$]&lt;br /&gt;&lt;br /&gt;Esto es, básicamente, la llamada &lt;a href="http://es.wikipedia.org/wiki/Algoritmo_de_la_divisi%C3%B3n"&gt;división euclídea&lt;/a&gt;. Matemáticamente este procedimiento de división es muy interesante y tiene muchas propiedades, pero carece de otras. En concreto, con esta división entera multiplicar divisor y dividendo por menos uno altera el resultado.&lt;br /&gt;&lt;br /&gt;[$$ \frac{a}{b} \ne \frac{-a}{-b} $$]&lt;br /&gt;&lt;br /&gt;Se puede probar con, por ejemplo, [$ \frac{7}{3} $] el cociente será [$2$] y el resto [$1$] mientras que [$ \frac{-7}{-3} $] tiene cociente [$3$] y resto [$2$]. No puedo obtener cociente [$2$] porque el resto tiene que ser positivo.&lt;br /&gt;&lt;br /&gt;Entonces, usemos una división más intuitiva. Por ejemplo, hacemos la división en los reales y luego redondeamos. Ahora bien, hay varios tipos de redondeo. Los más usuales son el redondeo por &lt;a href="http://en.wikipedia.org/wiki/Truncation"&gt;truncamiento&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Floor_and_ceiling_functions"&gt;por defecto, por exceso&lt;/a&gt; y &lt;a href="http://en.wikipedia.org/wiki/Rounding"&gt;al entero más cercano (con varias estrategias de desempate)&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Según usemos un tipo de división u otra, obtendremos el resto (es decir, el resultado del operador %) de una forma u otra, pero todas mediante la ecuación anterior para mantener consistencia. Despejamos de ella el resto y esa es nuestra definición del operador %.&lt;br /&gt;&lt;br /&gt;[$$ n\%d = r = n - dc = n - d \left[ \frac{n}{d} \right] $$]&lt;br /&gt;&lt;br /&gt;La división entre corchetes representa el cociente que cambiará según elijamos uno u otro redondeo. El resumen está en esta tabla.&lt;br /&gt;&lt;br /&gt;&lt;table style="border: solid 1px; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt; &lt;th&gt;&lt;/th&gt; &lt;th abbr="Trunca"&gt;Redondeo por truncamiento&lt;/th&gt; &lt;th abbr="Defecto"&gt;Redondeo por defecto&lt;/th&gt; &lt;th abbr="Exceso"&gt;Redondeo por exceso&lt;/th&gt; &lt;th abbr="Ceracno"&gt;Redondeo al más cercano&lt;/th&gt; &lt;th abbr="Euclídea"&gt;División euclídea&lt;/th&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;[$$\frac{3}{5}$$]&lt;/td&gt; &lt;td&gt;c=0&lt;br /&gt;r=3&lt;/td&gt; &lt;td&gt;c=0&lt;br /&gt;r=3&lt;/td&gt; &lt;td&gt;c=1&lt;br /&gt;r=-2&lt;/td&gt; &lt;td&gt;c=1&lt;br /&gt;r=-2&lt;/td&gt; &lt;td&gt;c=0&lt;br /&gt;r=3&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;[$$\frac{-3}{5}$$]&lt;/td&gt; &lt;td&gt;c=0&lt;br /&gt;r=-3&lt;/td&gt; &lt;td&gt;c=-1&lt;br /&gt;r=2&lt;/td&gt; &lt;td&gt;c=0&lt;br /&gt;r=-3&lt;/td&gt; &lt;td&gt;c=-1&lt;br /&gt;r=2&lt;/td&gt; &lt;td&gt;c=-1&lt;br /&gt;r=2&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;[$$\frac{3}{-5}$$]&lt;/td&gt; &lt;td&gt;c=0&lt;br /&gt;r=3&lt;/td&gt; &lt;td&gt;c=-1&lt;br /&gt;r=-2&lt;/td&gt; &lt;td&gt;c=0&lt;br /&gt;r=3&lt;/td&gt; &lt;td&gt;c=-1&lt;br /&gt;r=-2&lt;/td&gt; &lt;td&gt;c=0&lt;br /&gt;r=3&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;[$$\frac{-3}{-5}$$]&lt;/td&gt; &lt;td&gt;c=0&lt;br /&gt;r=-3&lt;/td&gt; &lt;td&gt;c=0&lt;br /&gt;r=-3&lt;/td&gt; &lt;td&gt;c=1&lt;br /&gt;r=2&lt;/td&gt; &lt;td&gt;c=1&lt;br /&gt;r=2&lt;/td&gt; &lt;td&gt;c=1&lt;br /&gt;r=2&lt;/td&gt; &lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Hay tres hechos importantes en esta tabla:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;En el redondeo por &lt;b&gt;truncamiento&lt;/b&gt; el signo del resto coincide con el signo del &lt;b&gt;dividendo&lt;/b&gt;.&lt;/li&gt;&lt;li&gt;En el redondeo por &lt;b&gt;defecto&lt;/b&gt; el signo del resto coincide con el signo del &lt;b&gt;divisor&lt;/b&gt; (y en el redondeo por exceso con su opuesto).&lt;/li&gt;&lt;li&gt;En el redondeo al &lt;b&gt;entero más cercano&lt;/b&gt; el resto es el &lt;b&gt;más cercano a cero&lt;/b&gt; posible.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="background-color: #666666;"&gt;&lt;span style="background-color: white;"&gt;&lt;span style="color: #666666;"&gt;Nota: La división que utilizamos cuando usamos el AND binario (&amp;amp;) para calcular rápidamente un módulo [$ a\% 2^n = a \&amp;amp; (2^n -1) $] es o bien la por defecto o la euclídea (tanto el divisor como el resto son positivos en este caso).&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ahora sólo queda ver qué lenguaje de programación usa qué tipo de división y módulo. La siguiente tabla extraída de la &lt;a href="http://en.wikipedia.org/wiki/Modulo_operation"&gt;Wikipedia&lt;/a&gt; lo lista.&lt;br /&gt;&lt;br /&gt;&lt;table style="border: solid 1px;"&gt;&lt;tbody&gt;&lt;tr&gt; &lt;th&gt;Lenguaje&lt;/th&gt; &lt;th&gt;Operador&lt;/th&gt; &lt;th abbr="Signo"&gt;El resultado tiene el mismo signo que&lt;/th&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/ActionScript"&gt;ActionScript&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Ada_(programming_language)" title="Ada (programming language)"&gt;Ada&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;rem&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Active_Server_Page" title="Active Server Page"&gt;ASP&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;Mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;No definido&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/ALGOL-68" title="ALGOL-68"&gt;ALGOL-68&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%×&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Euclidean_algorithm" title="Euclidean algorithm"&gt;Euclídea&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/AMPL"&gt;AMPL&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/AppleScript"&gt;AppleScript&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/BASIC"&gt;BASIC&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;Mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;No definido&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Bc_programming_language" title="Bc programming language"&gt;bc&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Bash_(Unix_shell)" title="Bash (Unix shell)"&gt;bash&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/C_(programming_language)" title="C (programming language)"&gt;C&lt;/a&gt; (ISO 1990)&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Depende de implementación&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/C99" title="C99"&gt;C (ISO 1999)&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/C%2B%2B"&gt;C++&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Depende de implementación&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/C_Sharp_(programming_language)" title="C Sharp (programming language)"&gt;C#&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Clarion_(programming_language)" title="Clarion (programming language)"&gt;CLARION&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Clojure"&gt;Clojure&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/ColdFusion"&gt;ColdFusion&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Common_Lisp"&gt;Common Lisp&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;rem&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/D_(programming_language)" title="D (programming language)"&gt;D&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Eiffel_(programming_language)" title="Eiffel (programming language)"&gt;Eiffel&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;\\&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Erlang_(programming_language)" title="Erlang (programming language)"&gt;Erlang&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;rem&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Euphoria_(programming_language)" title="Euphoria (programming language)"&gt;Euphoria&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;remainder&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/FileMaker"&gt;FileMaker&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;Mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Fortran"&gt;Fortran&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;modulo&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Game_Maker_Language" title="Game Maker Language"&gt;GML (Game Maker)&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Go_(programming_language)" title="Go (programming language)"&gt;Go&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Haskell_(programming_language)" title="Haskell (programming language)"&gt;Haskell&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;rem&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/J_(programming_language)" title="J (programming language)"&gt;J&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;|~&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Java_(programming_language)" title="Java (programming language)"&gt;Java&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/JavaScript"&gt;JavaScript&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Just_Basic" title="Just Basic"&gt;Just Basic&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;MOD&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Lua_(programming_language)" title="Lua (programming language)"&gt;Lua 5&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Lua_(programming_language)" title="Lua (programming language)"&gt;Lua 4&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod(x,y)&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Liberty_Basic" title="Liberty Basic"&gt;Liberty Basic&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;MOD&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/MathCad" title="MathCad"&gt;MathCad&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod(x,y)&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Maple_(software)"&gt;Maple (software)&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;e mod m&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Mathematica"&gt;Mathematica&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;Mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Microsoft_Excel"&gt;Microsoft Excel&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;=MOD()&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/MATLAB"&gt;MATLAB&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;rem&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Oberon_(programming_language)" title="Oberon (programming language)"&gt;Oberon&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;MOD&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Objective_Caml"&gt;Objective Caml&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Occam_(programming_language)" title="Occam (programming language)"&gt;Occam&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;\&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Pascal_(programming_language)" title="Pascal (programming language)"&gt;Pascal (Delphi)&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Pascal_(programming_language)" title="Pascal (programming language)"&gt;Pascal (ISO-7185 and ISO-10206)&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Euclidean_algorithm" title="Euclidean algorithm"&gt;Euclídea&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Perl"&gt;Perl&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/PHP"&gt;PHP&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/PL/I"&gt;PL/I&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor (ANSI PL/I)&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/PowerBuilder"&gt;PowerBuilder&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod(x,y)&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;&amp;nbsp;?&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/PowerShell" title="PowerShell"&gt;PowerShell&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Prolog"&gt;Prolog&lt;/a&gt; (ISO 1995)&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;rem&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Python_(programming_language)" title="Python (programming language)"&gt;Python&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/RealBasic" title="RealBasic"&gt;RealBasic&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;MOD&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/R_(programming_language)" title="R (programming language)"&gt;R&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/RPG_(programming_language)" title="RPG (programming language)"&gt;RPG&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%REM&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Ruby_(programming_language)" title="Ruby (programming language)"&gt;Ruby&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%, modulus()&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;remainder()&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Scheme_(programming_language)" title="Scheme (programming language)"&gt;Scheme&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;modulo&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;remainder&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Scheme_(programming_language)" title="Scheme (programming language)"&gt;Scheme&lt;/a&gt; R&lt;sup&gt;6&lt;/sup&gt;RS&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Euclidean_algorithm" title="Euclidean algorithm"&gt;Euclídea&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;mod0&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Más cercano a cero&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/SenseTalk"&gt;SenseTalk&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;modulo&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;rem&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Smalltalk"&gt;Smalltalk&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;\\&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/SQL"&gt;SQL&lt;/a&gt; (&lt;a href="http://en.wikipedia.org/wiki/SQL:1999"&gt;SQL:1999&lt;/a&gt;)&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod(x,y)&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Standard_ML"&gt;Standard ML&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;Int.rem&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Stata"&gt;Stata&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod(x,y)&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Euclidean_algorithm" title="Euclidean algorithm"&gt;Euclídea&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Tcl"&gt;Tcl&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Torque_Game_Engine" title="Torque Game Engine"&gt;Torque Game Engine&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Turing_(programming_language)"&gt;Turing (programming language)&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Verilog"&gt;Verilog&lt;/a&gt; (2001)&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/VHDL"&gt;VHDL&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;rem&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Visual_Basic"&gt;Visual Basic&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;Mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/X86_assembly_language" title="X86 assembly language"&gt;x86 Assembly&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;IDIV&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a class="new" href="http://en.wikipedia.org/w/index.php?title=ADEP_AUTO_language&amp;amp;action=edit&amp;amp;redlink=1" title="ADEP AUTO language (page does not exist)"&gt;ADEP_AUTO language&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;MODULO(x,y)&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;También existe el mismo problema relacionado con la operación equivalente en los reales (flotantes). Esta es la tabla en este caso.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;table style="border: solid 1px;"&gt;&lt;tbody&gt;&lt;tr&gt; &lt;th&gt;Lenguaje&lt;/th&gt; &lt;th&gt;Operador&lt;/th&gt; &lt;th abbr="Signo"&gt;El resultado tiene el mismo signo que&lt;/th&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/C_(programming_language)" title="C (programming language)"&gt;C&lt;/a&gt; (ISO 1990)&lt;/td&gt; &lt;td&gt;&lt;tt&gt;fmod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;&amp;nbsp;?&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/C99" title="C99"&gt;C (ISO 1999)&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;fmod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;remainder&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Más cercano a cero&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/C%2B%2B"&gt;C++&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;std::fmod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;&amp;nbsp;?&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/C_Sharp_(programming_language)" title="C Sharp (programming language)"&gt;C#&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/D_(programming_language)" title="D (programming language)"&gt;D&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;&amp;nbsp;?&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Common_Lisp"&gt;Common Lisp&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;rem&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Go_(programming_language)" title="Go (programming language)"&gt;Go&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;math.Fmod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Haskell_(programming_language)" title="Haskell (programming language)"&gt;Haskell&lt;/a&gt; (GHC)&lt;/td&gt; &lt;td&gt;&lt;tt&gt;Data.Fixed.mod'&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Java_(programming_language)" title="Java (programming language)"&gt;Java&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/JavaScript"&gt;JavaScript&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Objective_Caml"&gt;Objective Caml&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;mod_float&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Perl"&gt;Perl&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;POSIX::fmod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/PHP"&gt;PHP&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;fmod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Python_(programming_language)" title="Python (programming language)"&gt;Python&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;math.fmod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Ruby_(programming_language)" title="Ruby (programming language)"&gt;Ruby&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;%, modulus()&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Divisor&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;remainder()&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td rowspan="2"&gt;&lt;a href="http://en.wikipedia.org/wiki/Scheme_(programming_language)" title="Scheme (programming language)"&gt;Scheme&lt;/a&gt; R&lt;sup&gt;6&lt;/sup&gt;RS&lt;/td&gt; &lt;td&gt;&lt;tt&gt;flmod&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Euclidean_algorithm" title="Euclidean algorithm"&gt;Euclídea&lt;/a&gt;&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;tt&gt;flmod0&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Más cercano a cero&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td&gt;&lt;a href="http://en.wikipedia.org/wiki/Standard_ML"&gt;Standard ML&lt;/a&gt;&lt;/td&gt; &lt;td&gt;&lt;tt&gt;Real.rem&lt;/tt&gt;&lt;/td&gt; &lt;td&gt;Dividendo&lt;/td&gt; &lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Bueno. Entonces. Al final. ¿Cómo sé si un número es impar o no? Lo mejor es aprovechar que el resto cero es igual en todas las implementaciones y hacer algo así.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: cpp"&gt;bool impar(int n)&lt;br /&gt;{&lt;br /&gt; return (n%2) != 0;&lt;br /&gt; }&lt;/pre&gt;&lt;br /&gt;&lt;br/&gt;&lt;br /&gt;&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-4781366155740226891?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/4781366155740226891/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/04/divisiones-y-modulos-enteros.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/4781366155740226891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/4781366155740226891'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/04/divisiones-y-modulos-enteros.html' title='Divisiones y módulos enteros'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-604836085069939963</id><published>2011-04-19T20:55:00.001+02:00</published><updated>2011-04-19T20:55:00.977+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='manejo de memoria'/><category scheme='http://www.blogger.com/atom/ns#' term='miniSL'/><title type='text'>miniSL parte 12 - Limitaciones y uso del recolector de basura</title><content type='html'>Hasta ahora hemos hablado del &lt;a href="http://elmanantialdebits.blogspot.com/2011/01/minisl-parte-7-las-cadenas-internas.html"&gt;montículo&lt;/a&gt;, las &lt;a href="http://elmanantialdebits.blogspot.com/2010/11/minisl-parte-6-campos-de-celda.html"&gt;celdas&lt;/a&gt; y &amp;nbsp;cómo &lt;a href="http://elmanantialdebits.blogspot.com/2011/03/minisl-parte-10-operaciones-sobre-el.html"&gt;crearlas&lt;/a&gt;. Sin embargo, no hemos visto cómo se usa la recolección de basura implementada y, tampoco, sus limitaciones.&lt;br /&gt;&lt;br /&gt;La recolección de basura sirve para detectar celdas no usadas y marcarlas como tales. La forma de hacerlo es muy sencilla. Tenemos un conjunto raíz que son celdas que sabemos a ciencia cierta que son usadas de forma. A partir de ese conjunto exploramos qué otras celdas usan. El resto son celdas sin usar. Este algoritmo se denomina &lt;a href="http://en.wikipedia.org/wiki/Mark_and_sweep#Na.C3.AFve_mark-and-sweep"&gt;mark and sweep&lt;/a&gt; (marca y barre). El código para esto se adelantó en la parte 8, pero queda por saber cómo se usa exactamente.&lt;br /&gt;&lt;br /&gt;Lo importante son las limitaciones del algoritmo de recolección de basura implementado en miniSL. Son las siguientes.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;El algoritmo de mark and sweep usado &lt;b&gt;detiene la ejecución&lt;/b&gt;. Aunque este es el menor de nuestros problemas como veremos más adelante.&lt;/li&gt;&lt;li&gt;El algoritmo usado sólo usa el &lt;b&gt;entorno global&lt;/b&gt; (lo veremos con más detalle en la siguiente parte) como el &lt;b&gt;conjunto raíz&lt;/b&gt;. Esto quiere decir que no podemos llamar el algoritmo en medio de la ejecución del código porque la celda que contiene el entorno local de la función no forma parte del conjunto raíz.&lt;/li&gt;&lt;li&gt;En concreto, no podríamos lanzar el recolector de basura cuando notemos que nos hemos quedado sin memoria. Por ejemplo, en el caso de entrar en la línea 6 de la función Script::CreateCell(). Por esa razón, hemos de reservar una nueva celda y no reutilizar una antigua.&lt;/li&gt;&lt;li&gt;La estructura del recolector de basura no es incremental. El algoritmo mark and sweep usa dos conjuntos de celdas: las marcadas (usadas) y las no marcadas (no usadas). Para poder hacer un recolector de basura incremental hacen falta tres conjuntos llamados de celdas blancas, grises y negras.&lt;/li&gt;&lt;li&gt;Debido a todo esto, el propio &lt;b&gt;miniSL no puede llamar al recolector de basura&lt;/b&gt;. Lo tiene que hacer la aplicación que use el script.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Ni que decir tiene que estas limitaciones hacen el lenguaje miniSL inútil en la vida real, pero simplifican muchísimo el código. Nosotros lo que haremos será llamar al recolector de basura en cada ciclo del bucle de lectura-evaluación-impresión o (&lt;a href="http://en.wikipedia.org/wiki/REPL"&gt;REPL&lt;/a&gt;).&lt;br /&gt;Este bucle será ahora:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Lectura de una expresión.&lt;/li&gt;&lt;li&gt;Evaluación de la expresión.&lt;/li&gt;&lt;li&gt;Impresión del resultado.&lt;/li&gt;&lt;li&gt;Recolección de basura.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Veremos el REPL en la parte 32, ya que antes hemos de definir cómo evaluamos y cómo leemos una expresión. Hasta ahora sólo sabemos imprimir las celdas.&lt;br /&gt;&lt;br /&gt;En la siguiente entrada nos centraremos en el conjunto raíz de nuestro recolector de basura. Es decir, en el entorno global que contiene los símbolos definidos más generales.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-604836085069939963?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/604836085069939963/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/04/minisl-parte-12-limitaciones-y-uso-del.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/604836085069939963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/604836085069939963'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/04/minisl-parte-12-limitaciones-y-uso-del.html' title='miniSL parte 12 - Limitaciones y uso del recolector de basura'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-6744615321619169701</id><published>2011-04-15T19:41:00.000+02:00</published><updated>2011-04-15T19:41:00.707+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='varios'/><title type='text'>Grados de confianza gatunos</title><content type='html'>Como bien saben los que me siguen, de vez en cuando hago una excursión por temas no informáticos. Esta vez en el mundo de los gatos. Responderé a la pregunta ¿cómo sé si mi gato tiene confianza en mí o no?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://farm3.static.flickr.com/2305/1886978726_7d22be480a.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://farm3.static.flickr.com/2305/1886978726_7d22be480a.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;El gato amistoso de &lt;a href="http://shuflies.blogspot.com/2007/11/friendly-cat.html"&gt;Shu&lt;/a&gt; es de grado 4.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Cierta persona me dijo una vez que los grados son los siguientes.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Desconfiado&lt;/strong&gt;. El gato se aleja si te acercas a él. No tendrá menos de dos o tres metros de distancia entre tú y él.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Próximo&lt;/strong&gt;. Te puedes acercar a él, pero no se dejará tocar. O sólo se dejará tocar muy poco tiempo.&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Mimoso&lt;/strong&gt;. El gato se deja tocar, acariciar y rascar, pero sin hacer cosas raras. Cualquier movimiento, mirada, ruido, etc. hará que salga pitando. En general no es buena idea mirar a los ojos a los gatos. Es mejor parpadear lentamente para decir "no te estoy cazando".&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Escalador&lt;/strong&gt;. Una vez que está cómodo cerca de ti, el gato puede querer subirse encima. Generalmente no lo intentará cuando estés de pie. Podrá ser sobre las rodillas o sobre la barriga si estás tumbado.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Observador&lt;/strong&gt;. El gato se deja coger y deja que te pongas en pie con él. Si al gato no le gusta, se echará al suelo. Algunos gatos incluso te piden que los cojas poniendo sus patitas en tus rodillas. Realmente, una vez que se acostumbran, les encanta observar las cosas desde arriba.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Confiado&lt;/strong&gt;. El gato se deja coger y deja que andes con él. Algunos gatos pueden llegar incluso a abrazarse a ti. Este es el grado máximo, pero cualquier tontería hará que el gato pierda confianza y luego es difícil volverla a ganar. Así que mucho mimo.&lt;/li&gt;&lt;/ol&gt;Nota final: El ronroneo no es muy fiable. No siempre significa que el gato está contento. También puede ser que quiera algo, o que se haya olvidado que está ronroneando y siga ahí runrun.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-6744615321619169701?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/6744615321619169701/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/04/grados-de-confianza-gatunos.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6744615321619169701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6744615321619169701'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/04/grados-de-confianza-gatunos.html' title='Grados de confianza gatunos'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm3.static.flickr.com/2305/1886978726_7d22be480a_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-1469969185843762922</id><published>2011-04-11T19:31:00.006+02:00</published><updated>2011-04-11T19:31:00.223+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lenguajes de programación'/><title type='text'>Infija, prefija, postfija y circunfija</title><content type='html'>Expresión &lt;b&gt;infija&lt;/b&gt;. Es la usual. El operando (+) aparece entre los operadores (1 y 2).&lt;br /&gt;&lt;br /&gt;[$$ 1 + 2 $$]&lt;br /&gt;&lt;br /&gt;Expresión &lt;b&gt;prefija&lt;/b&gt;. El operador aparece antes de los operadores.&lt;br /&gt;&lt;br /&gt;[$$ + 1 2 $$]&lt;br /&gt;&lt;br /&gt;Es la forma natural en el lenguaje de programación &lt;a href="http://www.haskell.org/haskellwiki/Haskell"&gt;Haskell&lt;/a&gt;. Variante de esta es también [$ +(1,2) $] donde es más natural usar un operador alfabético como [$ f(1,2) $].&lt;br /&gt;&lt;br /&gt;Expresión &lt;b&gt;postfija&lt;/b&gt;. El operador aparece detrás de los operadores.&lt;br /&gt;&lt;br /&gt;[$$ 1 2 + $$]&lt;br /&gt;&lt;br /&gt;Expresión &lt;b&gt;circunfija&lt;/b&gt;. El operador rodea a los operadores. Esto es típico en los paréntesis.&lt;br /&gt;&lt;br /&gt;[$$ (1 2) $$]&lt;br /&gt;&lt;br /&gt;Es la forma usual del &lt;a href="http://en.wikipedia.org/wiki/Lisp_(programming_language)"&gt;LISP&lt;/a&gt;. Otra variante es con los operadores separados por coma o similar.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-1469969185843762922?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/1469969185843762922/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/04/infija-prefija-postfija-y-circunfija.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/1469969185843762922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/1469969185843762922'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/04/infija-prefija-postfija-y-circunfija.html' title='Infija, prefija, postfija y circunfija'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-630999224886203135</id><published>2011-04-07T11:12:00.000+02:00</published><updated>2011-04-07T11:12:14.282+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algoritmos'/><category scheme='http://www.blogger.com/atom/ns#' term='señales'/><category scheme='http://www.blogger.com/atom/ns#' term='audio y música'/><title type='text'>Frecuencia fraccional</title><content type='html'>&lt;b&gt;&lt;span style="color: red;"&gt;El problema&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Supongamos que tenemos un evento que se dispara a una frecuencia dada [$f_0$] (por ejemplo, una &lt;a href="http://en.wikipedia.org/wiki/Sampling_rate"&gt;frecuencia de muestreo&lt;/a&gt;). Llamaremos eventos básicos a estos eventos. Es fácil comprobar que puedo generar otros eventos derivados a partir de estos eventos básicos. Bastará tomar una frecuencia divisora [$f=f_0/k$] y lanzar un evento derivado cada [$k$] eventos básicos. Por ejemplo, si [$k=3$] tengo un evento derivado cada tres eventos básicos.&lt;br /&gt;&lt;br /&gt;Si trazamos el número de evento básico en el &lt;a href="http://es.answers.yahoo.com/question/index?qid=20070503155127AAw2nCH"&gt;eje de abscisas&lt;/a&gt; y el número de evento derivado en el eje de ordenadas, obtenemos una línea. En este caso, de pendiente [$1/3=f/f_0$].&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-2FZf2wKFzpc/TZ184GHVNvI/AAAAAAAAAGM/I4dc57khhLQ/s1600/FrecuenciaFraccional1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="179" src="http://4.bp.blogspot.com/-2FZf2wKFzpc/TZ184GHVNvI/AAAAAAAAAGM/I4dc57khhLQ/s320/FrecuenciaFraccional1.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;¿Pero qué ocurriría si la frecuencia es una fracción cualquiera de [$f_0$] y no exactamente un divisor?&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;El algoritmo&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En este caso a veces tendremos que contar [$k$] eventos básicos y otras veces [$k+1$]. No obtenemos una frecuencia exacta, pero en promedio sí será la [$f$] deseada. Pagamos un &lt;a href="http://es.wikipedia.org/wiki/Jitter"&gt;jitter&lt;/a&gt; por tener una frecuencia que no es divisora de la frecuencia básica.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-lvYOzhJJh8o/TZ185oZO59I/AAAAAAAAAGQ/n-R2SxAubLQ/s1600/FrecuenciaFraccional2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="144" src="http://3.bp.blogspot.com/-lvYOzhJJh8o/TZ185oZO59I/AAAAAAAAAGQ/n-R2SxAubLQ/s320/FrecuenciaFraccional2.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Lo interesante aquí es que seguimos obteniendo una recta, aunque ya no está centrada en el origen y tampoco tiene una pendiente [$1/k$]. Si llamo [$0\le r&amp;lt;1$] a la altura de intersección con el eje de ordenadas y [$t$] al número de evento básico (en definitiva, es el tiempo transcurrido) mi recta es&lt;br /&gt;&lt;br /&gt;[$$y=r+\frac{f}{f_0}t$$]&lt;br /&gt;&lt;br /&gt;El primer evento derivado se tendrá que lanzar cuando la recta corte a la línea [$y=1$]. Es decir&lt;br /&gt;&lt;br /&gt;[$$1=r+\frac{f}{f_0}t$$]&lt;br /&gt;&lt;br /&gt;Debido a que el resultado puede no ser un número entero, hemos de redondear al siguiente evento básico que llamaremos [$t_1$].&lt;br /&gt;&lt;br /&gt;[$$t_1=\left \lceil \frac{1-r}{f/f_0} \right \rceil$$]&lt;br /&gt;&lt;br /&gt;Ya sabemos cuándo lanzar el siguiente evento derivado: será en el evento básico [$t_1$]. Lo interesante aquí es que puedo trasladar de nuevo todo al origen de coordenadas y calcular el valor [$r$] para el siguiente evento derivado empezando desde cero. Usando exactamente las mismas ecuaciones.&lt;br /&gt;&lt;br /&gt;Este nuevo valor de [$r$], que llamaré [$r_1$], será el valor de [$r$] en [$t_1$] pero restando [$1$] para volver al origen de coordenadas.&lt;br /&gt;&lt;br /&gt;[$$r_1=r+\frac{f}{f_0}t_1-1$$]&lt;br /&gt;&lt;br /&gt;Con lo que el algoritmo sería&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Iniciamos con [$r=0$] y el valor [$f=f_0$] de frecuencia que deseemos.&lt;/li&gt;&lt;li&gt;Calculamos [$t_1$] y [$r_1$] a partir del valor de [$r, f$] y [$f_0$].&lt;/li&gt;&lt;li&gt;Esperamos [$t_1$] eventos básicos antes de lanzar un evento derivado.&lt;/li&gt;&lt;li&gt;Hacemos [$r \leftarrow r_1$] y vamos al paso 2&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;b&gt;La implementación&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Este algoritmo está muy bien, pero hay un detalle de implementación. Tanto el valor [$f/f_0$] como el valor [$r$] están en el intervalo [$[0,1)$]. No es descabellado usar una notación de &lt;a href="http://es.wikipedia.org/wiki/Coma_fija"&gt;coma fija&lt;/a&gt; para representarlo en [$n$] bits. Entonces, usando el subíndice [$p$] para la coma fija,&lt;br /&gt;&lt;br /&gt;[$$f_p=2^n \frac{f}{f_0} $$]&lt;br /&gt;[$$r_p=2^n r$$]&lt;br /&gt;&lt;br /&gt;Y las ecuaciones quedan&lt;br /&gt;&lt;br /&gt;[$$t_1=\left \lceil  \frac{2^n-r_p}{f_p} \right \rceil $$]&lt;br /&gt;[$$r_1=r_p+f_p t_1-2^n$$]&lt;br /&gt;&lt;br /&gt;La ecuación de [$t_1$] tiene un problema: el redondeo por exceso. Generalmente las divisiones enteras tienen &lt;a href="http://www.fdi.ucm.es/profesor/mozos/AEC/aritm_entera.pdf"&gt;redondeo por defecto&lt;/a&gt;. Es fácil hacer la conversión sumando el denominador menos uno.&lt;br /&gt;&lt;br /&gt;[$$t_1=\left \lceil  \frac{2^n-r_p}{f_p} \right \rceil=\left \lfloor \frac{2^n-r_p+f_p-1}{f_p} \right \rfloor $$]&lt;br /&gt;&lt;br /&gt;Y un paso más es darnos cuenta que [$2^n-1-r_p$] no es más que el &lt;a href="http://es.wikipedia.org/wiki/Complemento_a_uno"&gt;complemento a uno&lt;/a&gt; de [$r_p$] que notaremos [$ \sim r_p $].&lt;br /&gt;&lt;br /&gt;[$$t_1=\left \lfloor \frac{\sim r_p+f_p}{f_p} \right \rfloor $$]&lt;br /&gt;&lt;br /&gt;La ecuación de [$r_1$] puede simplificarse también ya que sumar o restar [$2^n$] no tiene efecto en &lt;a href="http://es.wikipedia.org/wiki/Aritm%C3%A9tica_modular"&gt;aritmética módulo&lt;/a&gt; [$2^n$] por lo que llegamos a&lt;br /&gt;&lt;br /&gt;[$$r_1=r_p+f_p t_1$$]&lt;br /&gt;&lt;br /&gt;El algoritmo sigue siendo el mismo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-630999224886203135?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/630999224886203135/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/04/frecuencia-fraccional.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/630999224886203135'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/630999224886203135'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/04/frecuencia-fraccional.html' title='Frecuencia fraccional'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-2FZf2wKFzpc/TZ184GHVNvI/AAAAAAAAAGM/I4dc57khhLQ/s72-c/FrecuenciaFraccional1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-3189518337828647845</id><published>2011-03-22T09:46:00.000+01:00</published><updated>2011-03-22T09:46:38.363+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='varios'/><title type='text'>Reunión del C++ Standards Committee en Madrid</title><content type='html'>Es la primera vez en la historia que el comité de estandarización del C++ se reúne en España. Durante unos días, del 21 al 26 de marzo de 2011, estarán en tierras hispanas. En teoría, pero sólo en teoría, las reuniones son públicas. Por si os queréis animar, toda la información está&amp;nbsp;&lt;a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2011/n3232.pdf"&gt;aquí&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-3189518337828647845?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/3189518337828647845/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/03/reunion-del-c-standards-committee-en.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/3189518337828647845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/3189518337828647845'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/03/reunion-del-c-standards-committee-en.html' title='Reunión del C++ Standards Committee en Madrid'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-7066950555525925869</id><published>2011-03-16T14:23:00.000+01:00</published><updated>2011-03-16T14:23:03.310+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='matemáticas'/><category scheme='http://www.blogger.com/atom/ns#' term='iteradores'/><category scheme='http://www.blogger.com/atom/ns#' term='programación genérica'/><category scheme='http://www.blogger.com/atom/ns#' term='semántica formal'/><title type='text'>Mónadas en un plis-plás</title><content type='html'>Como no hay blog de informática teórica que se precie sin un tutorial de mónadas, y aprovechando que &lt;a href="http://bartoszmilewski.wordpress.com/2011/01/09/monads-for-the-curious-programmer-part-1/"&gt;Milewski&lt;/a&gt; está dedicándole unos posts a esto, voy a explicar cómo entendí lo de las &lt;a href="http://en.wikipedia.org/wiki/Monad_(functional_programming)"&gt;mónadas&lt;/a&gt; (si es que lo entendí, claro).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;De los efectos secundarios y de cómo evitarlos&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Supongamos esta función.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;int f(int x)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; a=x+2;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;&amp;nbsp; return x*3;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Realmente, está haciendo dos cosas: retornar el triple y asignar el argumento más dos a una variable externa “a”. Esta segunda acción es lo que se llama un &lt;a href="http://en.wikipedia.org/wiki/Side_effect_(computer_science)"&gt;efecto secundario&lt;/a&gt; porque modifica el estado global del programa. En este caso, el valor de “a”.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh3.googleusercontent.com/-S2IgIV5SOD0/TYCwndzxvHI/AAAAAAAAAFs/W1wuAPJ-zrE/s1600/Monadas1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="259" src="https://lh3.googleusercontent.com/-S2IgIV5SOD0/TYCwndzxvHI/AAAAAAAAAFs/W1wuAPJ-zrE/s320/Monadas1.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Muchas veces &lt;a href="http://c2.com/cgi/wiki?AdvantagesOfFunctionalProgramming"&gt;no es conveniente tener efectos secundarios&lt;/a&gt;: se simplifica la concurrencia, se permite la transparencia referencial, se permiten más optimizaciones, facilita la comprensión del programa, etc. Si queremos evitar que la función “f” tenga efectos secundarios la única solución es forzar a que éstos sean devueltos también por el retorno. Llamaremos a esta nueva función “F” para distinguirla de la original “f” con efectos secundarios.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh6.googleusercontent.com/-5_OVaD8W2hI/TYCwq-NKQgI/AAAAAAAAAFw/nbd_P_7UMmE/s1600/Monadas2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="270" src="https://lh6.googleusercontent.com/-5_OVaD8W2hI/TYCwq-NKQgI/AAAAAAAAAFw/nbd_P_7UMmE/s320/Monadas2.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;El problema ahora es que tenemos que devolver dos tipos. Además, no hemos dicho nada de que la función “f” pueda hacer más de una asignación. Tampoco hemos hablado de cómo cambia este nuevo retorno el estado global. Lo mejor es abstraernos de todos estos detalles y decir que “F” devuelve asignaciones y un entero. Inventaremos el tipo “A&amp;lt;int&amp;gt;” para eso usando un &lt;a href="http://www.haskell.org/haskellwiki/Constructor"&gt;constructor de tipos&lt;/a&gt; "A".&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh6.googleusercontent.com/-UiKVytNBFr4/TYCwsIHliyI/AAAAAAAAAF0/KbOSuk1n238/s1600/Monadas3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="https://lh6.googleusercontent.com/-UiKVytNBFr4/TYCwsIHliyI/AAAAAAAAAF0/KbOSuk1n238/s320/Monadas3.png" width="216" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Así que “F” vuelve a ser una función normal y corriente con un tipo a devolver exótico que engloba tanto el retorno normal (el entero) como los efectos secundarios (las asignaciones).&lt;br /&gt;&lt;br /&gt;¡Pero hemos perdido una operación fundamental en la programación! ¿Cómo hacemos &lt;a href="http://en.wikipedia.org/wiki/Function_composition_(computer_science)"&gt;composiciones&lt;/a&gt;? ¿Cómo hacemos cosas como “f(f(5))”? Ahora que los tipos no coinciden, ¡no es posible escribir “F(F(5))”!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh3.googleusercontent.com/-avoC8yuqw0A/TYCws1df5II/AAAAAAAAAF4/rzlyaTdaMvY/s1600/Monadas4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="https://lh3.googleusercontent.com/-avoC8yuqw0A/TYCws1df5II/AAAAAAAAAF4/rzlyaTdaMvY/s320/Monadas4.png" width="175" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;La solución pasa por hacer explícita la aplicación. ¿Pero qué es una aplicación explícita?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;strong&gt;De la aplicación explícita y las restricciones que la composición le impone&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En esta sección sólo hablaremos de cosas conocidas: funciones puras sin efectos secundarios. Llamaremos “g” y “h” a estas funciones puras. Nos olvidaremos por ahora del tipo “A&amp;lt;int&amp;gt;” y de las funciones “f” y “F” con efectos secundarios.&lt;br /&gt;&lt;br /&gt;La aplicación explícita es sencillamente escribir “apply(x, g)” en vez de escribir “g(x)”.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh6.googleusercontent.com/-z4U358CGrJI/TYCwtyDiiLI/AAAAAAAAAF8/eV8SMxylgW4/s1600/Monadas5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="201" src="https://lh6.googleusercontent.com/-z4U358CGrJI/TYCwtyDiiLI/AAAAAAAAAF8/eV8SMxylgW4/s320/Monadas5.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Es únicamente un cambio en la notación, pero nos permite estudiar las propiedades de “apply” y realizar cosas tan potentes como la &lt;a href="http://en.wikipedia.org/wiki/Defunctionalization"&gt;defuncionalización&lt;/a&gt; (de la que no hablaremos aquí). En concreto, para que “apply” sea coherente con la composición, debe mantener sus dos propiedades: elemento neutro y asociativa.&lt;br /&gt;&lt;br /&gt;Para el elemento neutro hemos de introducir una función identidad. La llamaremos “id” y devuelve su argumento sin hacer nada de nada.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;int id(int v) {return v;} //Función identidad de los enteros&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Obviamente, componer esta función no debe hacer nada.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;apply(x, id) == x&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;apply(id(x), g) == g(x)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Para la asociativa introduciremos una función compuesta “h” que aplique consecutivamente dos funciones “g1” y “g2”. En notación matemática escribiríamos [$h=g_2 \circ g_1$].&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;int h(int v) { return apply(g1(v), g2); }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Entonces, aplicar esta función compuesta “h” es igual que aplicar consecutivamente “g1” y “g2”.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;apply(v, h) == apply(apply(v, g1), g2)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Con esto estamos seguros de que “apply” se comporta correctamente para la composición y podemos volver a pensar cómo solucionar el problema de la composición de la función “F”.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="color: #666666;"&gt;Nota: La propiedad asociativa aquí expuesta no parece ser la propiedad asociativa de toda la vida, pero si usamos “@” como operador infijo para el “apply” y la composición, entonces la propiedad queda algo así como “v@(g1@g2) = (v@g1)@g2” lo cual sí que se parece ya a la propiedad asociativa usual.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;De la mezcla de efectos secundarios con aplicaciones explícitas&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Lo interesante de hacer explícita la aplicación es que podemos adaptar el tipo de la misma a nuestros &lt;a href="http://elmanantialdebits.blogspot.com/2011/02/especificacion-de-requisitos-o.html"&gt;requisitos&lt;/a&gt;. Llamaremos “bind” a la aplicación con el tipo “A&amp;lt;int&amp;gt;” sobre funciones de tipo “int -&amp;gt; A&amp;lt;int&amp;gt;”, para no confundirla con “apply” que funciona sobre “int” y funciones “int -&amp;gt; int” únicamente.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;apply: int -&amp;gt; (int-&amp;gt;int) -&amp;gt; int&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;bind: A&amp;lt;int&amp;gt; -&amp;gt; (int -&amp;gt; A&amp;lt;int&amp;gt; ) -&amp;gt; A&amp;lt;int&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh5.googleusercontent.com/-WdGmPVq0sSk/TYCwvJggAYI/AAAAAAAAAGA/G49tRTL-aKw/s1600/Monadas6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="181" src="https://lh5.googleusercontent.com/-WdGmPVq0sSk/TYCwvJggAYI/AAAAAAAAAGA/G49tRTL-aKw/s320/Monadas6.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;El truco está en que “bind(xx, F)” toma los efectos secundarios de “xx” y los mezcla con los efectos secundarios del resultado de “F” para luego devolverlos en su resultado.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh4.googleusercontent.com/-upsetXVOJmA/TYCwwqVtHTI/AAAAAAAAAGE/T_YrhEpeYkI/s1600/Monadas7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="187" src="https://lh4.googleusercontent.com/-upsetXVOJmA/TYCwwqVtHTI/AAAAAAAAAGE/T_YrhEpeYkI/s320/Monadas7.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Pero queda el asunto de la composición que nos forzó a introducir el “bind”: debe cumplir exactamente las mismas propiedades que “apply”.&lt;br /&gt;&lt;br /&gt;La única salvedad es que “id” no debe ser la función identidad de los enteros. Tenemos que mantener el tipo “int -&amp;gt; A&amp;lt;int&amp;gt;” en las funciones. Así que se ha de convertir en una función que toma un entero y devuelve un “A&amp;lt;int&amp;gt;” de la manera más neutra posible. Es decir, sin efectos secundarios. También vamos a cambiar el nombre de esta función para no confundirla con la “id” original y la vamos a llamar “unit”.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh4.googleusercontent.com/-KKtj1pLmgPY/TYCwx1IITFI/AAAAAAAAAGI/5bpp_7e3M8U/s1600/Monadas8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="207" src="https://lh4.googleusercontent.com/-KKtj1pLmgPY/TYCwx1IITFI/AAAAAAAAAGI/5bpp_7e3M8U/s320/Monadas8.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Pues bien. Estas tres cosas son una mónada:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Un constructor de tipo como “A” que dado un tipo de retorno como “int” devuelve un tipo “A&amp;lt;int&amp;gt;” que engloba tanto ese tipo de retorno como los efectos secundarios.&lt;/li&gt;&lt;li&gt;Un par de funciones “bind” y “unit” que tienen los tipos antes mencionados.&lt;/li&gt;&lt;li&gt;Que se cumplan las propiedades de elemento neutro y asociativa.&lt;/li&gt;&lt;/ul&gt;&lt;span style="color: #666666;"&gt;&lt;span style="font-size: x-small;"&gt;Nota: El lector con conocimientos de álgebra habrá pensado “¿Elemento neutro y asociativa? ¿No era esto lo que definía un &lt;a href="http://en.wikipedia.org/wiki/Monoid"&gt;monoide&lt;/a&gt;? ¿Tiene que ver con el nombre de mónada?”. La respuesta es sí. Un monoide es lo que se forma con “int-&amp;gt;int” donde el tipo de entrada es igual al tipo de salida. Una mónada es la generalización donde los tipos no son siempre iguales.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;De los lugares en los que habitan las mónadas&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;La parquedad de los requisitos de las mónadas hace que aparezcan por todos los lados y no únicamente como modelo de efectos secundarios. Son en general un modelo de computación (ver ejemplo 1.1 en el &lt;a href="http://www.disi.unige.it/person/MoggiE/ftp/ic91.pdf"&gt;articulo original de Moggi&lt;/a&gt; para una lista de cosas que puede modelar una mónada).&lt;br /&gt;&lt;br /&gt;Por ejemplo, los &lt;a href="http://en.wikipedia.org/wiki/Null_pointer#Null_pointer"&gt;punteros con NULL&lt;/a&gt; se usan generalmente como mónadas. El constructor de tipo está claro que es el de los punteros. De “int” pasamos a “int*”. La función “unit” es simplemente obtener la dirección de un entero.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;int a;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;int* p=&amp;amp;a; // p=unit(a)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La función “bind” consiste en comprobar que el puntero no es NULL.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;return p==NULL ? NULL : p-&amp;gt;OperaYDevuelvePuntero() ;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;// return bind(p, OperaYDevuelvePuntero);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Es fácil comprobar las propiedades correspondientes con estas operaciones, pero aún hay más. Cualquier &lt;a href="http://en.wikipedia.org/wiki/Collection_(computer_science)"&gt;colección&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Iterator"&gt;iterable&lt;/a&gt; &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.33.5381"&gt;es una mónada&lt;/a&gt;. Sí, así a lo bestia: vectores, conjuntos, listas, mapas, tablas hash, etc. Todos son mónadas. El constructor de tipo es el de la colección que queramos. Por ejemplo, “vector&amp;lt;int&amp;gt;”.&lt;br /&gt;&lt;br /&gt;La función “unit” es bien sencilla: la colección con un único elemento.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;vector&amp;lt;int&amp;gt; v;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;v.push_back(3);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;// v=unit(3)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La función “bind” es equivalente a iterar y mezclar.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;vector&amp;lt;int&amp;gt; r;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;foreach (x in v) r.append(Procesa(x));&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;// r=bind(v, Procesa)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ojo que “Procesa” devuelve un vector y “append” mezcla vectores. Si “Procesa” fuera obtener la lista de divisores, entonces&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;bind([1, 6, 21], Procesa) = [1, 1, 2, 3, 6, 1, 3, 7, 21]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Esta propiedad del “bind” de separar, iterar y combinar es la que le da tanta utilidad. De hecho, debido a esto, “Procesa” también serviría para filtrar, transformar, unir y casi cualquier otra operación que se quiera realizar con la colección. Lo que no quita para que también la colección tenga sus operaciones propias no monádicas.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Pero con todo esto habría ya material para otra entrega en la que tendríamos que hablar de comprensiones monádicas, la notación “do” y empezar a usar muchas funciones anónimas.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-7066950555525925869?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/7066950555525925869/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/03/monadas-en-un-plis-plas.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/7066950555525925869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/7066950555525925869'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/03/monadas-en-un-plis-plas.html' title='Mónadas en un plis-plás'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh3.googleusercontent.com/-S2IgIV5SOD0/TYCwndzxvHI/AAAAAAAAAFs/W1wuAPJ-zrE/s72-c/Monadas1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-7172175802020799443</id><published>2011-03-13T13:46:00.001+01:00</published><updated>2011-04-07T20:59:28.952+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='manejo de memoria'/><category scheme='http://www.blogger.com/atom/ns#' term='miniSL'/><title type='text'>miniSL parte 11 - Operaciones sobre el montículo</title><content type='html'>Ya hemos descrito el montículo en la &lt;a href="http://elmanantialdebits.blogspot.com/2011/01/minisl-parte-7-las-cadenas-internas.html"&gt;parte octava&lt;/a&gt;. Ahora vamos a realizar dos tipos de operaciones sobre él. El primer grupo es el de las operaciones de reserva de memoria, mientras que el segundo grupo son las operaciones de liberado de memoria. En este post veremos las del primer grupo.&lt;br /&gt;Inicialmente tenemos la creación de una celda genérica con dos referencias.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL&amp;amp; Script::CreateCell(CELL_TYPE ct, CELL* first, CELL* second)&lt;br /&gt;{&lt;br /&gt; CELL* p;&lt;br /&gt; if(m_FirstUnused==NULL)&lt;br /&gt; {&lt;br /&gt;  CELL c;&lt;br /&gt;  m_Cells.push_back(c);&lt;br /&gt;  p=&amp;amp;m_Cells.back();&lt;br /&gt; }&lt;br /&gt; else&lt;br /&gt; {&lt;br /&gt;  p=m_FirstUnused;&lt;br /&gt;  m_FirstUnused=p-&amp;gt;next_unused;&lt;br /&gt; }&lt;br /&gt; p-&amp;gt;mark=false;&lt;br /&gt; p-&amp;gt;type=ct;&lt;br /&gt; p-&amp;gt;head=first;&lt;br /&gt; p-&amp;gt;tail=second;&lt;br /&gt; return *p;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Somos astutos y antes de reservar memoria (con el &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;push_back&lt;/span&gt;) vemos si tenemos alguna celda libre ya reservada. Esto es algo ineficiente porque la celda que reservemos no vuelve a liberarse realmente, sólo se apunta como liberada. Todo sea por ser simples en la implementación.&lt;br /&gt;Para crear celdas de otros tipos, primero creamos una celda genérica con &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;Script::CreateCell&lt;/span&gt; y luego cambiamos sus campos específicos. Por ejemplo, para una cadena no interna.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL&amp;amp; Script::CreateString(STRING const&amp;amp; val)&lt;br /&gt;{&lt;br /&gt; CELL&amp;amp; c=CreateCell(STRING_LIT);&lt;br /&gt; c.string_val=new STRING(val);&lt;br /&gt; return c;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;En el caso de una cadena interna hemos de recurrir a las técnicas comentadas en la &lt;a href="http://elmanantialdebits.blogspot.com/2010/12/minisl-parte-7-las-cadenas-internas.html"&gt;parte séptima&lt;/a&gt;. En concreto, usaremos el mapa &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;m_InternedStrings&lt;/span&gt; para comprobar si ya tenemos o no la cadena internada. Si es así, la usamos. Si no, la creamos y la guardamos en el &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;m_InternedStrings&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL&amp;amp; Script::CreateName(STRING const&amp;amp; val)&lt;br /&gt;{&lt;br /&gt; STRING_MAP::const_iterator i=m_InternedStrings.find(val);&lt;br /&gt; if(i==m_InternedStrings.end())&lt;br /&gt; {&lt;br /&gt;  CELL&amp;amp; c=CreateCell(NAME_CODE);&lt;br /&gt;  i=m_InternedStrings.insert(std::make_pair(val, &amp;amp;c)).first;&lt;br /&gt;  c.string_val=&amp;amp;i-&amp;gt;first;&lt;br /&gt; }&lt;br /&gt; return *i-&amp;gt;second;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Aquí se ve el truco comentado en la parte séptima: se usa la propia clave del mapa como la cadena interna. Esto nos fuerza a realizar la inserción en dos partes. Primero la celda de tipo &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;NAME_CODE&lt;/span&gt; sin ningún puntero iniciado y, luego, se inicia el puntero &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;string_val&lt;/span&gt; a la dirección de la clave &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;i-&amp;gt;first&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Para crear un entorno necesitamos crear adicionalmente su tabla de símbolos.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL&amp;amp; Script::CreateEnvir(CELL* parent)&lt;br /&gt;{&lt;br /&gt; CELL&amp;amp; c=CreateCell(ENVIR_VAL);&lt;br /&gt; c.envir_table=new ENVIR_TABLE;&lt;br /&gt; c.parent_envir=parent;&lt;br /&gt; return c;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Y más sencillo aún son las funciones nativas porque son trozos de código que no se elimina nunca. En este caso necesitamos una función especial meramente porque el tipo es &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;NATIVE&lt;/span&gt; y no &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;CELL&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL&amp;amp; Script::CreateNative(NATIVE native)&lt;br /&gt;{&lt;br /&gt; CELL&amp;amp; c=CreateCell(NATIVE_VAL);&lt;br /&gt; c.native=native;&lt;br /&gt; return c;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Con esto está la creación de celdas completada. En el siguiente apartado veremos cómo se usa el recolector de basura (&lt;a href="http://elmanantialdebits.blogspot.com/2011/01/minisl-parte-7-las-cadenas-internas.html"&gt;garbage collector&lt;/a&gt;) del cual ya adelantamos algo en la &lt;a href="http://elmanantialdebits.blogspot.com/2011/01/minisl-parte-7-las-cadenas-internas.html"&gt;parte octava&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-7172175802020799443?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/7172175802020799443/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/03/minisl-parte-10-operaciones-sobre-el.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/7172175802020799443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/7172175802020799443'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/03/minisl-parte-10-operaciones-sobre-el.html' title='miniSL parte 11 - Operaciones sobre el montículo'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-3756292156468489054</id><published>2011-03-04T10:40:00.000+01:00</published><updated>2011-03-04T10:40:27.405+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='video y gráficos'/><category scheme='http://www.blogger.com/atom/ns#' term='interfaces'/><title type='text'>Estándar WebGL 1.0 publicado</title><content type='html'>Llevamos unos días con noticias sobre nuevos estándares que no paramos. Ayer, tres de marzo, salió otro estándar. Esta vez es &lt;a href="http://www.khronos.org/news/press/releases/khronos-releases-final-webgl-1.0-specification"&gt;WebGL&lt;/a&gt;, un contexto de renderización para el elemento &lt;a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html"&gt;CANVAS de HTML5&lt;/a&gt;. Cada vez los programadores de Javascript sobre la web tienen más y más recursos multimedia. ¿Será capaz el HTML5 de desbancar a otros sistemas como &lt;a href="http://www.error500.net/web/html5-flash-lucha-estandares"&gt;Flash o Silverlight como se proponía&lt;/a&gt;?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-3756292156468489054?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/3756292156468489054/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/03/estandar-webgl-10-publicado.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/3756292156468489054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/3756292156468489054'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/03/estandar-webgl-10-publicado.html' title='Estándar WebGL 1.0 publicado'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-106137195656171392</id><published>2011-03-03T11:03:00.000+01:00</published><updated>2011-03-03T11:03:43.181+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algoritmos'/><category scheme='http://www.blogger.com/atom/ns#' term='teoría de la información'/><title type='text'>Tenemos finalistas para el SHA-3</title><content type='html'>Los SHA (&lt;a href="http://en.wikipedia.org/wiki/Secure_Hash_Algorithm"&gt;secure hash algorithm&lt;/a&gt;) son una serie de algoritmos establecidos por la &lt;a href="http://www.nist.gov/index.html"&gt;Agencia Americana de Tecnología&lt;/a&gt; para la criptografía. Si no sabes mucho de criptografía, puedes aprender &lt;a href="http://www.freearchive.org/o/907da43df4038f882bf25159cb3f26708735a60f3bff881372b3bb8f6cf677be"&gt;todo lo que hace falta saber en una hora&lt;/a&gt;. Parece ser que según van saliendo los algoritmos se van buscando sus fallos y, por ejemplo, ya te avisan de que no uses el SHA-1 y que vayas pasándote al SHA-2. Es probable que de aquí a poco también empiecen a aparecer grietas en este último por lo que es importante ir preparándose para el SHA-3.&lt;br /&gt;&lt;br /&gt;El SHA-3 no está decidido aún, pero el concurso ha llegado &lt;a href="http://csrc.nist.gov/groups/ST/hash/sha-3/Round3/index.html"&gt;a su final&lt;/a&gt; donde sólo quedan cinco candidatos posibles. Los nombres de los algoritmos son:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;BLAKE&lt;/li&gt;&lt;li&gt;Grøstl&lt;/li&gt;&lt;li&gt;JH&lt;/li&gt;&lt;li&gt;Keccak&lt;/li&gt;&lt;li&gt;Skein&lt;/li&gt;&lt;/ul&gt;Para los curiosos que quieran saber qué es lo que cuenta para que un algoritmo de hash criptográfico sea bueno, el informe de su evaluación está &lt;a href="http://csrc.nist.gov/groups/ST/hash/sha-3/Round2/documents/Round2_Report_NISTIR_7764.pdf"&gt;aquí&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-106137195656171392?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/106137195656171392/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/03/tenemos-finalistas-para-el-sha-3.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/106137195656171392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/106137195656171392'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/03/tenemos-finalistas-para-el-sha-3.html' title='Tenemos finalistas para el SHA-3'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-2448706904112657789</id><published>2011-03-02T16:58:00.000+01:00</published><updated>2011-03-02T16:58:38.104+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='varios'/><title type='text'>Unicode 6.0</title><content type='html'>Hace unos días se publicó la nueva versión del estándar &lt;a href="http://www.unicode.org/"&gt;Unicode&lt;/a&gt;. No hay cambios significativos, únicamente la introducción de nuevos caracteres. La lista diferencial de cambios está &lt;a href="http://www.unicode.org/charts/PDF/Unicode-6.0/"&gt;aquí&lt;/a&gt; y las tablas de códigos completas &lt;a href="http://www.unicode.org/Public/6.0.0/charts/"&gt;aquí&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-2448706904112657789?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/2448706904112657789/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/03/unicode-60.html#comment-form' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/2448706904112657789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/2448706904112657789'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/03/unicode-60.html' title='Unicode 6.0'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-2804477162557344732</id><published>2011-02-27T11:13:00.000+01:00</published><updated>2011-02-27T11:13:00.423+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='varios'/><title type='text'>Minipost para el ahorro de energía</title><content type='html'>Simplificando mucho.&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt; &lt;td style="border: 1px solid; padding: 10px;"&gt;&lt;/td&gt; &lt;td style="border: 1px solid; padding: 10px;"&gt;¿Se apaga la CPU?&lt;/td&gt; &lt;td style="border: 1px solid; padding: 10px;"&gt;¿Se apaga la RAM?&lt;/td&gt; &lt;td style="border: 1px solid; padding: 10px;"&gt;¿Se cierra la sesión?&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td style="border: 1px solid; padding: 10px;"&gt;Encendido&lt;/td&gt; &lt;td style="border: 1px solid; padding: 10px;"&gt;No&lt;/td&gt; &lt;td style="border: 1px solid; padding: 10px;"&gt;No&lt;/td&gt; &lt;td style="border: 1px solid; padding: 10px;"&gt;No&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td style="border: 1px solid; padding: 10px;"&gt;Suspendido (Modo S3)&lt;/td&gt; &lt;td style="background: #fcc; border: 1px solid; padding: 10px;"&gt;Sí&lt;/td&gt; &lt;td style="border: 1px solid; padding: 10px;"&gt;No&lt;/td&gt; &lt;td style="border: 1px solid; padding: 10px;"&gt;No&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td style="border: 1px solid; padding: 10px;"&gt;Hibernado (Modo S4)&lt;/td&gt; &lt;td style="background: #fcc; border: 1px solid; padding: 10px;"&gt;Sí&lt;/td&gt; &lt;td style="background: #fcc; border: 1px solid; padding: 10px;"&gt;Sí&lt;/td&gt; &lt;td style="border: 1px solid; padding: 10px;"&gt;No&lt;/td&gt; &lt;/tr&gt;&lt;tr&gt; &lt;td style="border: 1px solid; padding: 10px;"&gt;Apagado&lt;/td&gt; &lt;td style="background: #fcc; border: 1px solid; padding: 10px;"&gt;Sí&lt;/td&gt; &lt;td style="background: #fcc; border: 1px solid; padding: 10px;"&gt;Sí&lt;/td&gt; &lt;td style="background: #fcc; border: 1px solid; padding: 10px;"&gt;Sï&lt;/td&gt; &lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Nota: Para los modos ver &lt;a href="http://en.wikipedia.org/wiki/Acpi"&gt;ACPI&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-2804477162557344732?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/2804477162557344732/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/02/minipost-para-el-ahorro-de-energia.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/2804477162557344732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/2804477162557344732'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/02/minipost-para-el-ahorro-de-energia.html' title='Minipost para el ahorro de energía'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-5981773409402180362</id><published>2011-02-23T13:53:00.000+01:00</published><updated>2011-02-23T13:53:24.519+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='miniSL'/><title type='text'>miniSL parte 10 - Extracción de valores</title><content type='html'>Si &lt;a href="http://elmanantialdebits.blogspot.com/2011/02/minisl-parte-9-imprimiendo-celdas.html"&gt;imprimir los valores de una celda fue fácil&lt;/a&gt;, obtenerlos va a ser aún más fácil. Podríamos &lt;a href="http://elmanantialdebits.blogspot.com/2010/11/minisl-parte-6-campos-de-celda.html"&gt;leer directamente los campos de una celda&lt;/a&gt;, pero es más conveniente encapsular las operaciones más comunes en una única función miembro de CELL que lance una excepción si algo va mal.&lt;br /&gt;&lt;pre class="brush: cpp"&gt;int GetInteger()const&lt;br /&gt;{&lt;br /&gt; if(type==INT_LIT)&lt;br /&gt;  return int_val;&lt;br /&gt; throw L"Integer expected";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;bool GetBoolean()const&lt;br /&gt;{&lt;br /&gt; if(type==BOOL_VAL)&lt;br /&gt;  return bool_val;&lt;br /&gt; throw L"Boolean expected";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;STRING const&amp;amp; GetString()const&lt;br /&gt;{&lt;br /&gt; if(type==STRING_LIT)&lt;br /&gt;  return *string_val;&lt;br /&gt; throw L"String expected";&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;El único caso no trivial aparece cuando queremos explorar o modificar los entornos. Recordemos que cada celda de entorno tiene una tabla de símbolos (un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;ENVIR_TABLE&lt;/span&gt; que era un typedef de &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;std::map&amp;lt;CELL*, CELL*&amp;amp;gt&lt;/span&gt;;) en el campo &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;envir_table&lt;/span&gt; y un entorno padre en el campo &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;parent_envir&lt;/span&gt;. Estas complejidades son necesarias para código con una forma similar a esta:&lt;br /&gt;&lt;pre&gt;&amp;gt; define(a, 5)&lt;br /&gt;[]&lt;br /&gt;&amp;gt; define(f, lambda([x],[x+a]))&lt;br /&gt;[]&lt;br /&gt;&amp;gt; f(3)&lt;br /&gt;8&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Cuando se definen &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;a&lt;/span&gt; y &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f&lt;/span&gt;, se hace en el entorno global. Cuando se llama a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f(3)&lt;/span&gt; se crea un nuevo entorno local donde &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;x&lt;/span&gt; se vincula a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;3&lt;/span&gt;. ¿Pero cuánto vale a en el entorno local? ¡No está definida en el entorno local, está definida en el entorno global! La solución es crear un enlace, el del entorno padre, de la forma indicada en el diagrama de abajo.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-2H-1z8yRUGU/TWUCmvVMNGI/AAAAAAAAAFo/oLh-cVyUkMY/s1600/EntornoPadre.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="260" src="http://1.bp.blogspot.com/-2H-1z8yRUGU/TWUCmvVMNGI/AAAAAAAAAFo/oLh-cVyUkMY/s400/EntornoPadre.gif" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;De esta manera están disponibles tanto la &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;a&lt;/span&gt; como la propia &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f&lt;/span&gt; dentro del cuerpo de la &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f&lt;/span&gt;. De todo esto, lo único que necesitamos por ahora son dos funciones en la clase &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;Script&lt;/span&gt;. La primera hace la búsqueda de un nombre que se realiza siempre de la misma forma. Primero, buscamos en el entorno actual y, si no se encuentra, repetimos recursivamente buscando en el entorno padre.&lt;br /&gt;&lt;pre class="brush: cpp"&gt;CELL* Script::FindName(CELL&amp;amp; name, CELL&amp;amp; envir)&lt;br /&gt;{&lt;br /&gt; //Try to find the name in current environment&lt;br /&gt; ENVIR_TABLE::const_iterator i=envir.envir_table-&amp;gt;find(&amp;amp;name);&lt;br /&gt; if(i!=envir.envir_table-&amp;gt;end())&lt;br /&gt;  return i-&amp;gt;second;&lt;br /&gt;&lt;br /&gt; //Failed, try parent&lt;br /&gt; if(envir.parent_envir!=NULL)&lt;br /&gt;  return FindName(name, *envir.parent_envir);&lt;br /&gt;&lt;br /&gt; //Failed also, not found&lt;br /&gt; return NULL;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;La segunda, para cambiar un nombre, hace casi lo mismo: buscamos el nombre en el entorno actual cambiándolo si lo encontramos y, si no lo encontramos, llamamos recursivamente la función en el entorno padre. Si no hay entorno padre es que el nombre no estaba definido.&lt;br /&gt;&lt;pre class="brush: cpp"&gt;void Script::ChangeName(CELL&amp;amp; name, CELL&amp;amp; envir, CELL&amp;amp; value)&lt;br /&gt;{&lt;br /&gt; //Try to find the name in current environment&lt;br /&gt; ENVIR_TABLE::iterator i=envir.envir_table-&amp;gt;find(&amp;amp;name);&lt;br /&gt; if(i!=envir.envir_table-&amp;gt;end())&lt;br /&gt; {&lt;br /&gt;  (*envir.envir_table)[&amp;amp;name]=&amp;amp;value;&lt;br /&gt;  return;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; //Failed, try parent&lt;br /&gt; if(envir.parent_envir!=NULL)&lt;br /&gt;  return ChangeName(name, *envir.parent_envir, value);&lt;br /&gt;&lt;br /&gt; //Failed also, not found&lt;br /&gt; throw L"Name to be changed is undefined";&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;También necesitaremos la operación de definición de un nombre en el entorno actual como hace &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define&lt;/span&gt;, sin buscar en los entornos padre, pero coincide exactamente con la operación básica de inserción en &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;std::map&lt;/span&gt; así que, aunque sea algo incorrecto al romper la &lt;a href="http://es.wikipedia.org/wiki/Abstracci%C3%B3n_(inform%C3%A1tica)"&gt;abstracción sobre la implementación&lt;/a&gt;, usaremos directamente la clase &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;std::map&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Hasta ahora sólo hemos explicado cómo leer una celda. En la siguiente entrada hablaremos de la creación de celdas.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-5981773409402180362?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/5981773409402180362/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/02/minisl-parte-10-extraccion-de-valores.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/5981773409402180362'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/5981773409402180362'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/02/minisl-parte-10-extraccion-de-valores.html' title='miniSL parte 10 - Extracción de valores'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-2H-1z8yRUGU/TWUCmvVMNGI/AAAAAAAAAFo/oLh-cVyUkMY/s72-c/EntornoPadre.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-8634669122266833637</id><published>2011-02-15T10:28:00.001+01:00</published><updated>2011-02-19T14:47:39.803+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lenguajes de programación'/><title type='text'>Purgando conocimiento</title><content type='html'>Leo en &lt;a href="http://www.reddit.com/r/programming/comments/fkt7t/nemerle_factor_alice_ml_and_other_programming/"&gt;Reddit&lt;/a&gt; que los administradores de &lt;a href="http://www.wikipedia.org/"&gt;Wikipedia&lt;/a&gt; se están dedicando a hacer purga de los lenguajes de programación menos conocidos como &lt;a href="http://en.wikipedia.org/wiki/Nemerle"&gt;Nemerle&lt;/a&gt; (una maravilla de lenguaje basado en macros), &lt;a href="http://en.wikipedia.org/wiki/Factor_(programming_language)"&gt;Factor&lt;/a&gt; (de hecho leo el &lt;a href="http://factor-language.blogspot.com/"&gt;blog de su creador&lt;/a&gt;), &lt;a href="http://en.wikipedia.org/wiki/Alice_ML"&gt;Alice ML&lt;/a&gt; y otros.&lt;br /&gt;&lt;br /&gt;Me causa una gran pena porque conocí estos lenguajes (y otros más) gracias a la Wikipedia. Quizás haya que ser de una universidad americana para que te tengan en cuenta.&lt;br /&gt;&lt;br /&gt;Edit: Parece que Factor aún no ha caído. Los otros dos están borrados ya.&lt;br /&gt;Edit2: 19-02-2011 Nemerle ha vuelto a aparecer, pero Alice ML sigue borrado.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-8634669122266833637?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/8634669122266833637/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/02/purgando-conocimiento.html#comment-form' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/8634669122266833637'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/8634669122266833637'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/02/purgando-conocimiento.html' title='Purgando conocimiento'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-7559928799961300963</id><published>2011-02-10T13:26:00.000+01:00</published><updated>2011-02-10T13:26:27.046+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lenguaje natural'/><title type='text'>¿Especificación de requisitos o especificación de requerimientos?</title><content type='html'>Otro caso en el que usar Google no nos ayuda a discernir cuál está bien o cual está mal. Si &lt;a href="http://www.google.es/search?client=opera&amp;amp;rls=es-ES&amp;amp;q=%22especificaci%C3%B3n+de+requerimientos%22&amp;amp;sourceid=opera&amp;amp;ie=utf-8&amp;amp;oe=utf-8&amp;amp;channel=suggest"&gt;usamos "requerimientos"&lt;/a&gt; obtenemos más o menos las mismas páginas que si &lt;a href="http://www.google.es/search?client=opera&amp;amp;rls=es-ES&amp;amp;q=%22especificaci%C3%B3n+de+requisitos%22&amp;amp;sourceid=opera&amp;amp;ie=utf-8&amp;amp;oe=utf-8&amp;amp;channel=suggest"&gt;usamos "requisitos"&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Por otra parte, el diccionario lo dice claramente: "&lt;a href="http://buscon.rae.es/draeI/SrvltGUIBusUsual?TIPO_BUS=1&amp;amp;LEMA=requisito"&gt;requisito&lt;/a&gt;" es la circunstancia que se debe dar mientras que "&lt;a href="http://buscon.rae.es/draeI/SrvltGUIBusUsual?TIPO_BUS=1&amp;amp;LEMA=requerimiento"&gt;requerimiento&lt;/a&gt;" es la acción de requerir algo (es sinónimo de "petición", "demanda", etc.)&lt;br /&gt;&lt;br /&gt;Resumiendo:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;"Especificación de requisitos" es la especificación de las circunstancias que se deben dar (para que el programa sea correcto).&lt;/li&gt;&lt;li&gt;"Especificación de requerimientos" sería la especificación de las peticiones o demandas. Obviamente, esta es la que se usa mal.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-7559928799961300963?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/7559928799961300963/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/02/especificacion-de-requisitos-o.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/7559928799961300963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/7559928799961300963'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/02/especificacion-de-requisitos-o.html' title='¿Especificación de requisitos o especificación de requerimientos?'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-6449679938777728170</id><published>2011-02-08T15:40:00.000+01:00</published><updated>2011-02-08T15:40:10.527+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lenguajes de programación'/><category scheme='http://www.blogger.com/atom/ns#' term='macros'/><title type='text'>Las tres cosas que diferencian funciones y macros</title><content type='html'>Hace tiempo &lt;a href="http://elmanantialdebits.blogspot.com/2009/10/macros-vs-funciones.html"&gt;hablé sobre las similitudes entre funciones y macros&lt;/a&gt;. Esta vez voy a hablar de sus diferencias.&lt;br /&gt;&lt;br /&gt;Hay tres cosas que una macro puede hacer y una función no.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: red;"&gt;1) El control del flujo de ejecución&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Una función no puede controlar qué pasa con sus argumentos. No puede controlar si se evalúan o no. No puede recuperarse de un error si uno de sus argumentos falla. No puede hacer nada. De hecho, cuando evaluamos&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f(1+2, 3*4)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Lo que ocurre es que primero evaluamos los argumentos.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f(3, 12)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Y luego le pasamos el control a "f" que hará lo que tenga que hacer. Esto no es problema en un lenguaje funcional ya que no vamos a tener efectos secundarios de ningún tipo, pero sí que lo es en un lenguaje con efectos secundarios.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;haz_dos_veces(print("a"))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Si "haz_dos_veces" es una función, vamos a evaluar primero los argumentos. Se imprimirá una vez "a" y pasaremos el resultado (posiblemente de &lt;a href="http://en.wikipedia.org/wiki/Unit_type"&gt;tipo unitario&lt;/a&gt;) a la función que, haga lo que haga, no va a poder reimprimir la "a".&lt;br /&gt;&lt;br /&gt;En el caso de que tuviéramos referencias a funciones entonces todo cambia. Ahora se puede pasar en el argumento la referencia a la función que hace lo que yo quiero.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define_funcion f() { print("a") }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;haz_dos_veces(f)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ahora sí que "haz_dos_veces" puede llamar dos veces a la función pasada e imprimir "a" dos veces. Así que cuando hay referencias a funciones esta diferencia entre macros y funciones no cuenta tanto; pero cuenta porque hay que envolver en una función el código que queremos pasar.&lt;br /&gt;&lt;br /&gt;Las macros pueden hacerlo sin envolver nada.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define_macro haz_dos_veces(f) { f; f }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;haz_dos_veces(print("a"))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Se expande a&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;print("a");print("a")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;strong&gt;2) Manejo de entornos&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;El ejemplo más claro de esta posibilidad es la definición de símbolos en el entorno dinámico, &lt;a href="http://elmanantialdebits.blogspot.com/2009/08/higiene-en-tu-macro.html"&gt;aunque no sea lo más seguro&lt;/a&gt; y &lt;a href="http://elmanantialdebits.blogspot.com/2009/10/transparencia-en-tu-macro.html"&gt;fácil de entender&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define_macro haz_a_cero() { a=0; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;a=1;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;haz_a_cero(); //Expande a &amp;nbsp; a=0&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;print(a) //Imprime 0 porque ha sido modificado por la macro&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Si fuera una función, hacer "a" valer cero dentro de la función sólo modifica el entorno local de la función.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define_funcion haz_a_cero() { a=0; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;a=1;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;haz_a_cero();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;print(a) //Imprime 1 porque no se ha modificado nada&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Como ocurría con el apartado anterior, si tenemos referencias a variables (punteros), una función podría simular este comportamiento.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;define_funcion haz_cero(x) {*x=0; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;a=1;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;haz_cero(&amp;amp;a);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;print(a) //Imprime 0&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Sin embargo, la inspección del entorno la hemos tenido que hacer en la llamada con el "&amp;amp;a". La función no puede elegir qué símbolo va a cambiar. Si hubiéramos pasado "&amp;amp;b" la función no se quejaría y cambiaría "b". Con la macro esto no ocurría ya que ella misma inspeccionaba el entorno dinámico.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: red;"&gt;&lt;strong&gt;3) Procesado de código&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Esta es la diferencia realmente grande. Los argumentos de una macro pueden significar algo completamente distinto a lo que se cree porque la macro puede procesar el código y cambiarlo. Por ejemplo, la macro "bromista" cambia los "+" por "-".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;bromista(5+3) //Expande a &amp;nbsp;5-3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Con este tipo de transformaciones lo que realmente tenemos es la capacidad de modificar la semántica. En cierta forma, estamos ya acostumbrados. Supongamos un lenguaje en el que tengamos que declarar variables antes de usarlas, como &lt;a href="http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf"&gt;JavaScript&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;f(a=3); //Error, a no definido.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;var a=3; //Define a y le da el valor 3&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;El significado de "=" cuando se evalúa y cuando se escribe tras "var" es distinto. Si contemplamos "var" como una macro, lo que hace es buscar expresiones con la forma identificador-igual-valor. Para cada una de esas expresiones (en vez de evaluarlas como hizo la función "f"), define la variable en el entorno y le da ese valor.&lt;br /&gt;&lt;br /&gt;Es esta capacidad de analizar y transformar el código de sus argumentos lo que hacen las macros únicas y superiores a las funciones.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-6449679938777728170?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/6449679938777728170/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/02/las-tres-cosas-que-diferencian.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6449679938777728170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/6449679938777728170'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/02/las-tres-cosas-que-diferencian.html' title='Las tres cosas que diferencian funciones y macros'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-2336411311660855813</id><published>2011-02-02T13:02:00.001+01:00</published><updated>2011-02-02T13:17:51.667+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='miniSL'/><title type='text'>miniSL parte 9 - Imprimiendo celdas</title><content type='html'>La impresión de celdas en miniSL es relativamente sencilla usando un algoritmo recursivo. Según el tipo de celda, imprimimos su contenido tal y como se describió en la &lt;a href="http://elmanantialdebits.blogspot.com/2010/11/minisl-parte-5-tipos-de-celda.html"&gt;quinta parte de esta serie&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;void CELL::Print(OSTREAM&amp;amp; o)const&lt;br /&gt;{&lt;br /&gt; switch(type)&lt;br /&gt; {&lt;br /&gt; default:  o &amp;lt;&amp;lt; L"{{**UNKNOWN**}}"; break;&lt;br /&gt; case UNUSED: o &amp;lt;&amp;lt; L"{{**UNUSED**}}"; break;&lt;br /&gt; case INT_LIT: o &amp;lt;&amp;lt; std::dec &amp;lt;&amp;lt; int_val; break;&lt;br /&gt; case BOOL_VAL: o &amp;lt;&amp;lt; (bool_val ? L"true" : L"false"); break;&lt;br /&gt; case LAMBDA_VAL:o &amp;lt;&amp;lt; L"{{ "; code-&amp;gt;Print(o); o &amp;lt;&amp;lt; L" }}"; break;&lt;br /&gt; case NATIVE_VAL:o &amp;lt;&amp;lt; L"{{NATIVE}}"; break;&lt;/pre&gt;&lt;br /&gt;Hasta aquí ningún extraño aparte de usar una llamada recursiva para imprimir el contenido del código en las funciones lambda. Para imprimir las cadenas debemos tener cuidado ya que pueden contener caracteres de control que no son imprimibles y hay que escaparlos.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;case STRING_LIT:PrintEscapedString(o, *string_val); break;&lt;br /&gt; case NAME_CODE: o &amp;lt;&amp;lt; L"@"; PrintEscapedString(o, *string_val); break;&lt;/pre&gt;&lt;br /&gt;Es importante notar que los nombres no son únicamente cadenas. Las cadenas se evalúan a sí mismas mientras que los nombres se evalúan buscándolos en el entorno actual. Para distinguirlos bien, pondremos el prefijo @ delante de ellos. De esta manera permitimos usar nombres con espacios o símbolos en ellos. Veremos que será muy útil para extender la sintaxis.&lt;br /&gt;&lt;br /&gt;La impresión de las listas la vamos a hacer en la función CELL::PrintList() para así poder reutilizar el código a la hora de imprimir celdas COMBINE_CODE.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;case CONS_CTOR: case EMPTY_LIT:&lt;br /&gt;  o &amp;lt;&amp;lt; L"[";&lt;br /&gt;  PrintList(o, L", ");&lt;br /&gt;  o &amp;lt;&amp;lt; L"]";&lt;br /&gt;  break;&lt;br /&gt; case COMBINE_CODE:&lt;br /&gt;  op-&amp;gt;Print(o);&lt;br /&gt;  o &amp;lt;&amp;lt; L"(";&lt;br /&gt;  operands-&amp;gt;PrintList(o, L", ");&lt;br /&gt;  o &amp;lt;&amp;lt; L")";&lt;br /&gt;  break;&lt;/pre&gt;&lt;br /&gt;Finalmente, la impresión de un entorno se realiza iterando sobre él.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;case ENVIR_VAL: o &amp;lt;&amp;lt; L"{{ENVIR ";&lt;br /&gt;  for(ENVIR_TABLE::const_iterator i=envir_table-&amp;gt;begin(); i!=envir_table-&amp;gt;end(); ++i)&lt;br /&gt;  {&lt;br /&gt;   o &amp;lt;&amp;lt; *i-&amp;gt;first-&amp;gt;string_val &amp;lt;&amp;lt; L"= ";&lt;br /&gt;   i-&amp;gt;second-&amp;gt;Print(o);&lt;br /&gt;  }&lt;br /&gt;  o &amp;lt;&amp;lt; L"}}";&lt;br /&gt;  break;&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Nos queda por implementar entonces, la impresión de listas y de cadenas escapadas. Ambas funciones son relativamente directas.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;void CELL::PrintList(OSTREAM&amp;amp; o, STRING const&amp;amp; separator)const&lt;br /&gt;{&lt;br /&gt; for(CELL const* c=this; c-&amp;gt;type==CONS_CTOR; c=c-&amp;gt;tail)&lt;br /&gt; {&lt;br /&gt;  if(c!=this)&lt;br /&gt;   o &amp;lt;&amp;lt; separator;&lt;br /&gt;  c-&amp;gt;head-&amp;gt;Print(o);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void CELL::PrintEscapedString(OSTREAM&amp;amp; o, STRING const&amp;amp; s)&lt;br /&gt;{&lt;br /&gt; o &amp;lt;&amp;lt; L"\"";&lt;br /&gt; for(STRING::const_iterator i=s.begin(); i!=s.end(); ++i)&lt;br /&gt; {&lt;br /&gt;  if(*i&amp;lt;32) o &amp;lt;&amp;lt; L"\\x" &amp;lt;&amp;lt; std::hex &amp;lt;&amp;lt; (unsigned int)(unsigned)*i &amp;lt;&amp;lt; L";";&lt;br /&gt;  else  o &amp;lt;&amp;lt; *i;&lt;br /&gt; }&lt;br /&gt; o &amp;lt;&amp;lt; L"\"";&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Por ejemplo, la impresión de una lista, una función lambda y un booleano se ve así:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;[1, 2, 3]&lt;br /&gt;{{ [[@"x"], [@"+"(@"x", @"x")]] }}&lt;br /&gt;true&lt;/pre&gt;&lt;br /&gt;Se observa que tanto la lista como el booleano es directamente código, pero la función lambda es un valor que no es representable directamente en código. Por eso lo vamos a escribir entre dobles llaves. Estos valores deben obtenerse como el resultado de una llamada. De hecho, también se pueden imprimir celdas del tipo COMBINE_CODE que son precisamente esas llamadas. Así, f(x,y) se imprimiría así:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;@"f"(@"x", @"y")&lt;/pre&gt;&lt;br /&gt;De esta manera podemos ver los valores y el código que tenemos en el montículo, pero no nos basta con verlos. Debemos también poder utilizarlos. Para eso vamos a introducir una serie de funciones que nos permita extraer valores. Estas funciones van a ser también muy sencillas. Las dejaremos para la siguiente entrada.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-2336411311660855813?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/2336411311660855813/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/02/minisl-parte-9-imprimiendo-celdas.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/2336411311660855813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/2336411311660855813'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/02/minisl-parte-9-imprimiendo-celdas.html' title='miniSL parte 9 - Imprimiendo celdas'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-8601099773097102190</id><published>2011-01-27T11:01:00.000+01:00</published><updated>2011-01-27T11:01:32.168+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='narrativa'/><title type='text'>Escenas y escenas.</title><content type='html'>Como viene &lt;a href="http://elmanantialdebits.blogspot.com/2010/06/caracterizacion.html"&gt;siendo habitual&lt;/a&gt;, de vez en cuando hablo sobre otros temas para descansar de la informática. Espero que se me disculpen estas pequeñas infidelidades.&lt;br /&gt;&lt;br /&gt;Cuando estamos creando una historia lo más usual es que llegue un momento en el que tengamos la línea argumental completamente especificada. Sabemos qué va a ocurrir y cuándo. Qué personajes están involucrados y qué repercusión tienen sus actos. Sin embargo, hay que concretar todo lo ideado en escenas. Esta fase es el desglose en escenas (&lt;a href="http://www.gointothestory.com/2009/06/scene-by-scene-breakdown-shakespeare-in.html"&gt;scene breakdown&lt;/a&gt;) o &lt;a href="http://www.elmulticine.com/glosario2.php?orden=73"&gt;escaleta&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;No puedo decir cómo se hace la escaleta porque, honestamente, no lo sé, pero sí que puedo dar una idea de las escenas con las que vamos a acabar. Son, resumidamente, de tres tipos.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Escenas estructurantes. Son las escenas que dan información sobre la &lt;a href="http://elmanantialdebits.blogspot.com/2010/04/un-pequeno-vuelo.html"&gt;línea argumental&lt;/a&gt;. Hacen avanzar la historia o bien mostrando actos de los personajes o bien dándonos información. Ya sabéis, "Luke, yo soy tu padre" no es un acto en sí, pero es un gran trozo de información. Es interesante hacer notar también la llamada clausura. Es lo que no se muestra, pero que el lector o espectador se imagina. Una escena puede no mostrar nada directamente, pero seguir influyendo en la historia debido a que insta al lector a imaginar lo que ha ocurrido. ¿O alguien vio cómo mataron al caballo en El Padrino?&lt;/li&gt;&lt;li&gt;Escenas caracterizantes. Estas escenas no transmiten nueva información sobre la línea argumental, pero sí sobre los personajes. Muestran un aspecto de su personalidad, o ponen a los personajes en una situación en la cual deben mostrar su personalidad. El ejemplo típico serían las escenas iniciales de las películas de James Bond. No suelen tener nada que ver con el resto de la película, pero dejan claro quién es el jefe. Una escena de este tipo también puede servir para crear un ambiente, una situación, describir un lugar o incluso sensaciones. Por ejemplo, esas escenas en las películas de terror que parece que va a pasar algo, que hay alguien en la casa, pero al final sólo es el vecino que ha perdido las llaves.&lt;/li&gt;&lt;li&gt;Escenas irrelevantes. Escenas de relleno que pueden ser quitadas.&lt;/li&gt;&lt;/ol&gt;Rara vez una escena es de uno de estos tipos únicamente. Lo que sí está claro es que las escenas irrelevantes son las que aburren ya que no contribuyen a la historia. Entiendo que es importante detectar escenas de este tipo (o que sean en gran medida irrelevantes) y tratar de eliminarlas.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-8601099773097102190?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/8601099773097102190/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/01/escenas-y-escenas.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/8601099773097102190'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/8601099773097102190'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/01/escenas-y-escenas.html' title='Escenas y escenas.'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-7174133231112203188</id><published>2011-01-20T11:01:00.002+01:00</published><updated>2011-01-20T11:01:00.722+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rangos'/><category scheme='http://www.blogger.com/atom/ns#' term='algoritmos'/><category scheme='http://www.blogger.com/atom/ns#' term='lenguajes de programación'/><category scheme='http://www.blogger.com/atom/ns#' term='interfaces'/><category scheme='http://www.blogger.com/atom/ns#' term='matemáticas'/><category scheme='http://www.blogger.com/atom/ns#' term='semántica formal'/><title type='text'>¿Secuencial o Paralelo?</title><content type='html'>Este es un resumen de la charla de &lt;a href="http://www.infoq.com/presentations/Thinking-Parallel-Programming"&gt;Guy Steele sobre paralelismo en Strange Loop&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="border: 1px solid;"&gt;&lt;span style="color: red;"&gt;&lt;b&gt;SECUENCIAL&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;&lt;td style="border: 1px solid;"&gt;&lt;span style="color: red;"&gt;&lt;b&gt;PARALELO&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid;"&gt;Se ejecuta un código A, luego se usa el resultado de A en otro código B.&lt;/td&gt;&lt;td style="border: 1px solid;"&gt;Se ejecutan los códigos A y B independientemente. Luego se mezclan los resultados.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid;"&gt;Reusa el espacio. Sólo hay que almacenar un resultado.&lt;/td&gt;&lt;td style="border: 1px solid;"&gt;Usa espacio extra para desacoplar los cálculos.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid;"&gt;Procesa una cosa cada vez y va acumulando resultados.&lt;/td&gt;&lt;td style="border: 1px solid;"&gt;Descompone y mezcla resultados. Divide y vencerás.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid;"&gt;Requiere iniciar el acumulador con el elemento neutro de la operación.&lt;br /&gt;&lt;pre&gt;acc=elem_neutro;&lt;br /&gt;for(i=0; i&amp;lt;n; ++i)&lt;br /&gt;&amp;nbsp; &amp;nbsp;acc=acc @ &amp;nbsp;x[i]&lt;/pre&gt;&lt;/td&gt;&lt;td style="border: 1px solid;"&gt;Requiere asociatividad en la operación para ir mezclando resultados. No se puede procesar en paralelo:&lt;br /&gt;[$$ x_0 \star (x_1 \star (... )) $$]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_70qaZ1HIj6A/TTQC1gRzV1I/AAAAAAAAAFc/PU7jJe9EmP4/s1600/Secuencial.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="185" src="http://3.bp.blogspot.com/_70qaZ1HIj6A/TTQC1gRzV1I/AAAAAAAAAFc/PU7jJe9EmP4/s200/Secuencial.gif" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/td&gt;&lt;td style="border: 1px solid;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_70qaZ1HIj6A/TTQC6nLhVqI/AAAAAAAAAFg/TZFYhIR00mQ/s1600/Paralelo.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="119" src="http://3.bp.blogspot.com/_70qaZ1HIj6A/TTQC6nLhVqI/AAAAAAAAAFg/TZFYhIR00mQ/s200/Paralelo.gif" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border: 1px solid;"&gt;Se basa en trucos para optimizar.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Reordenación de instrucciones.&lt;/li&gt;&lt;li&gt;Desplegado de bucles.&lt;/li&gt;&lt;li&gt;Reutilización de registros.&lt;/li&gt;&lt;li&gt;Ejecución especulativa.&lt;/li&gt;&lt;li&gt;Predicción de saltos.&lt;/li&gt;&lt;li&gt;etc.&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;/td&gt;&lt;td style="border: 1px solid;"&gt;Se basa en propiedades algebraicas para optimizar.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Asociativa: La forma de agrupar operaciones no importa.&lt;/li&gt;&lt;li&gt;Conmutativa: El orden de los operandos no importa.&lt;/li&gt;&lt;li&gt;Idempotente: Las repeticiones no importan.&lt;/li&gt;&lt;li&gt;Identidad: El elemento neutro puede ser ignorado.&lt;/li&gt;&lt;li&gt;Cero: El resto de elementos puede ser ignorado.&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Así que hay que hacer que el programador deje de pensar en acumuladores y pase a pensar en propiedades algebraicas. Es decir, usar &lt;a href="http://en.wikipedia.org/wiki/Catamorphism"&gt;catamorfismos&lt;/a&gt; en vez de bucles. Los catamorfismos no son más que funciones que toman una estructura de datos y devuelven un valor a partir de ella con la propiedad de que son morfismos. En el caso de sumar una lista de números sería algo así como convertir la concatenación en suma.&lt;br /&gt;&lt;br /&gt;[$$ f( [ 3, 5 ] .. [4, 7] ) = f( [3,5] ) + f( [4, 7] ) $$]&lt;br /&gt;&lt;br /&gt;Esto significa a su vez que hay que buscar una operación con las propiedades algebraicas que deseemos (o podamos obtener), lo cual puede llevar a comprender más profundamente el problema.&lt;br /&gt;&lt;br /&gt;La especificación del catamorfismo es similar al uso de sumatorios en matemáticas. No se especifica el orden de la suma, sólo que hay que sumar los elementos.&lt;br /&gt;&lt;br /&gt;[$$ \sum_{i=1}^{n} {x_i} $$]&lt;br /&gt;&lt;br /&gt;En programación esto se tendría que hacer usando funciones de alto nivel como &lt;a href="http://en.wikipedia.org/wiki/Fold_(higher-order_function)"&gt;fold&lt;/a&gt; pero asumiendo la asociatividad.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;fold_assoc( suma, [3, 5, 4, 7] )&lt;/pre&gt;&lt;br /&gt;Así el compilador podría optimizar usando paralelismo sin que el programador tuviera que luchar con sincronizaciones y demás.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-7174133231112203188?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/7174133231112203188/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/01/secuencial-o-paralelo.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/7174133231112203188'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/7174133231112203188'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/01/secuencial-o-paralelo.html' title='¿Secuencial o Paralelo?'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_70qaZ1HIj6A/TTQC1gRzV1I/AAAAAAAAAFc/PU7jJe9EmP4/s72-c/Secuencial.gif' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-7670834999264993120</id><published>2011-01-19T10:56:00.000+01:00</published><updated>2011-01-19T10:56:38.120+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='varios'/><title type='text'>El BBVA le da un premio a Donald Knuth</title><content type='html'>Van un poco tarde porque este hombre lleva desde 1963 publicando libros, pero bueno. Todo sea por que se conozca algo más en España al &lt;a href="http://en.wikipedia.org/wiki/TeX"&gt;creador de TeX&lt;/a&gt;, del algoritmo que &lt;a href="http://en.wikipedia.org/wiki/Knuth%E2%80%93Bendix_completion_algorithm"&gt;convierte ecuaciones en reglas de reescritura confluentes&lt;/a&gt;, de &lt;a href="http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm"&gt;otro que busca subcadenas&lt;/a&gt; y de &lt;a href="http://en.wikipedia.org/wiki/The_Art_of_Computer_Programming"&gt;El Arte de Programar Computadores&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Fuente: &lt;a href="http://www.elmundo.es/elmundo/2011/01/18/ciencia/1295354085.html"&gt;El Mundo&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-7670834999264993120?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/7670834999264993120/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/01/el-bbva-le-da-un-premio-donald-knuth.html#comment-form' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/7670834999264993120'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/7670834999264993120'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/01/el-bbva-le-da-un-premio-donald-knuth.html' title='El BBVA le da un premio a Donald Knuth'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-5121586203026569963</id><published>2011-01-15T13:06:00.002+01:00</published><updated>2011-03-13T13:39:55.579+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='manejo de memoria'/><category scheme='http://www.blogger.com/atom/ns#' term='algoritmos'/><category scheme='http://www.blogger.com/atom/ns#' term='miniSL'/><title type='text'>miniSL parte 8 - El montículo</title><content type='html'>Llega el momento de pensar dónde y cómo almacenar las celdas en memoria. La forma en la que vamos a hacerlo es la siguiente. Usaremos un std::deque para reservar memoria. Los &lt;a href="http://es.wikipedia.org/wiki/Cola_doblemente_terminada"&gt;deques&lt;/a&gt; permiten ir añadiendo memoria conforme se necesite y no mueven los bloques de memoria una vez reservados.&lt;br /&gt;&lt;br /&gt;De todas las celdas que hayamos reservado, usaremos unas y tendremos otras libres, sin usar. Utilizaremos la recolección de basura para pasar celdas antes usadas pero ahora ociosas a celdas sin usar y libres para su reciclado.&lt;br /&gt;&lt;br /&gt;La recolección de basura es un procedimiento que puede ser o bien muy complejo o bien muy simple. En este caso, y teniendo en cuenta que miniSL intenta implementarlo todo de la forma más simple y reducida, nos inclinaremos por el algoritmo más simple de recolección de basura. El llamado &lt;a href="http://blogs.msdn.com/b/abhinaba/archive/2009/01/30/back-to-basics-mark-and-sweep-garbage-collection.aspx"&gt;mark and sweep&lt;/a&gt; (marca y barre).&lt;br /&gt;&lt;br /&gt;El mark and sweep funciona en dos pasos. El primer paso detecta las celdas en uso. ¿Cómo hace eso? Muy simple. O bien es una celda raíz (que siempre está en uso) o bien nos referencian desde otra celda en uso. Estas celdas en uso son marcadas. El segundo paso es barrer (=reciclar) todas las celdas que no están marcadas y limpiar la marca en las que sí.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_70qaZ1HIj6A/TTGMHYU2OVI/AAAAAAAAAFY/QWf3kl_4VXk/s1600/GarbageCollection.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="197" src="http://1.bp.blogspot.com/_70qaZ1HIj6A/TTGMHYU2OVI/AAAAAAAAAFY/QWf3kl_4VXk/s320/GarbageCollection.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;La siguiente figura muestra a) el conjunto raíz, b) los punteros entre celdas y c) las marcas. Las celdas que en c) no estén marcadas (las blancas) serán las reclamadas por el recolector de basura y pasarán a estar libres para un posterior uso.&lt;br /&gt;&lt;br /&gt;En la implementación lo primero que tenemos es el std::deque de almacenamiento de celdas.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL_STORAGE m_Cells;&lt;/pre&gt;&lt;br /&gt;Recordemos que definíamos CELL_STORAGE así:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;typedef std::deque&amp;lt;CELL&amp;gt; CELL_STORAGE;&lt;/pre&gt;&lt;br /&gt;También necesitamos saber si hay celdas libres. Las pondremos todas en una lista simplemente enlazada que empieza en el campo m_FirstUnused.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL* m_FirstUnused;&lt;/pre&gt;&lt;br /&gt;Para reservar una celda primero vemos si hay alguna libre. Si no, aumentamos el std::deque reservando memoria para una celda más. Esto no es muy económico ya que lo interesante habría sido devolver la memoria usada por las celdas libres. Estamos actuando más bien como un &lt;a href="http://en.wikipedia.org/wiki/Memory_pool"&gt;pool&lt;/a&gt; que como un gestor de memoria.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL&amp;amp; Script::CreateCell(CELL_TYPE ct, CELL* first, CELL* second)&lt;br /&gt;{&lt;br /&gt; CELL* p;&lt;br /&gt; if(m_FirstUnused==NULL)&lt;br /&gt; {&lt;br /&gt;  CELL c;&lt;br /&gt;  m_Cells.push_back(c);&lt;br /&gt;  p=&amp;amp;m_Cells.back();&lt;br /&gt; }&lt;br /&gt; else&lt;br /&gt; {&lt;br /&gt;  p=m_FirstUnused;&lt;br /&gt;  m_FirstUnused=p-&amp;gt;next_unused;&lt;br /&gt; }&lt;br /&gt; p-&amp;gt;mark=false;&lt;br /&gt; p-&amp;gt;type=ct;&lt;br /&gt; p-&amp;gt;head=first;&lt;br /&gt; p-&amp;gt;tail=second;&lt;br /&gt; return *p;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;El algoritmo de marcado es recursivo de manera que explora todo el grafo de referencias (punteros entre celdas) en profundidad. Dependiendo del tipo de celda, alguno o ninguno de sus campos serán referencias que hay que explorar. Evitamos los posibles ciclos no volviendo a marcar las celdas ya marcadas.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;void Script::GCMark(CELL* c)&lt;br /&gt;{&lt;br /&gt; if(c==NULL || c-&amp;gt;mark)&lt;br /&gt; return;&lt;br /&gt;&lt;br /&gt; c-&amp;gt;mark=true;&lt;br /&gt;&lt;br /&gt; switch(c-&amp;gt;type)&lt;br /&gt; {&lt;br /&gt; case UNUSED:  throw L"Marking unused cell";&lt;br /&gt; case CONS_CTOR:  GCMark(c-&amp;gt;head); GCMark(c-&amp;gt;tail);  break;&lt;br /&gt; case LAMBDA_VAL: GCMark(c-&amp;gt;code); GCMark(c-&amp;gt;closure);  break;&lt;br /&gt; case COMBINE_CODE: GCMark(c-&amp;gt;op);  GCMark(c-&amp;gt;operands); break;&lt;br /&gt;&lt;br /&gt; case ENVIR_VAL:&lt;br /&gt;  GCMark(c-&amp;gt;parent_envir);&lt;br /&gt;  for(ENVIR_TABLE::const_iterator i=c-&amp;gt;envir_table-&amp;gt;begin(); i!=c-&amp;gt;envir_table-&amp;gt;end(); ++i)&lt;br /&gt;  {&lt;br /&gt;   GCMark(i-&amp;gt;first);&lt;br /&gt;   GCMark(i-&amp;gt;second);&lt;br /&gt;  }&lt;br /&gt;  break;&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;El caso más laborioso es el de los entornos. En ellos hay que iterar su contenido y explorarlo para el marcado.&lt;br /&gt;El borrado ocurre en la rutina de barrido. Es simple y su única dificultad radica en las celdas especiales que contienen algún dato externo. Ya vimos uno de estos casos en las cadenas internas. Las cadenas normales y los entornos son otros casos similares. Cada uno de ellos ha de tener un borrado específico.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;int Script::GCSweep()&lt;br /&gt;{&lt;br /&gt; int count=0;&lt;br /&gt; for(CELL_STORAGE::iterator i=m_Cells.begin(); i!=m_Cells.end(); ++i)&lt;br /&gt; {&lt;br /&gt;  if(i-&amp;gt;mark)&lt;br /&gt;  {&lt;br /&gt;   i-&amp;gt;mark=false;&lt;br /&gt;   continue;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  if(i-&amp;gt;type==UNUSED)&lt;br /&gt;   continue;&lt;br /&gt;&lt;br /&gt;  ++count;&lt;br /&gt;&lt;br /&gt;  switch(i-&amp;gt;type)&lt;br /&gt;  {&lt;br /&gt;  case STRING_LIT: delete i-&amp;gt;string_val;      break;&lt;br /&gt;  case ENVIR_VAL:  delete i-&amp;gt;envir_table;      break;&lt;br /&gt;  case NAME_CODE:  m_InternedStrings.erase(*i-&amp;gt;string_val); break;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  i-&amp;gt;type=UNUSED;&lt;br /&gt;  i-&amp;gt;next_unused=m_FirstUnused;&lt;br /&gt;  m_FirstUnused=&amp;amp;*i;&lt;br /&gt; }&lt;br /&gt; return count;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Como conjunto raíz vamos a tener únicamente el entorno global. Añadimos una referencia a la celda de entorno de que lo contenga y lo marcamos en la recolección de basura.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;int Script::GarbageCollect()&lt;br /&gt;{&lt;br /&gt; GCMark(m_GlobalEnvir);&lt;br /&gt; return GCSweep();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;A partir de aquí hemos de recordar que el entorno global es una celda destacada. De hecho, estará referenciada en la clase Script.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL* m_GlobalEnvir;&lt;/pre&gt;&lt;br /&gt;El lector atento habrá visto que hemos retornado el número de celdas barridas en el recolector de basura. El retorno del número de celdas es un buen sistema para depurar el recolector de basura, pero no es el único. De hecho, nos ofrece poca información. Otro sistema que va a ser útil no sólo para el recolector de basura sino también para observar los resultados de las evaluaciones es la impresión de celdas. En la siguiente entrada nos dedicaremos a esta tarea.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-5121586203026569963?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/5121586203026569963/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/01/minisl-parte-7-las-cadenas-internas.html#comment-form' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/5121586203026569963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/5121586203026569963'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/01/minisl-parte-7-las-cadenas-internas.html' title='miniSL parte 8 - El montículo'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_70qaZ1HIj6A/TTGMHYU2OVI/AAAAAAAAAFY/QWf3kl_4VXk/s72-c/GarbageCollection.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-439024405404343981</id><published>2011-01-03T18:00:00.000+01:00</published><updated>2011-01-03T18:00:08.992+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='varios'/><title type='text'>2010, el primer año ciberpunk de la historia</title><content type='html'>O eso es lo que dice &lt;a href="http://herbsutter.com/2010/12/31/2010-cyberpunk-world/"&gt;Herb Sutter&lt;/a&gt; en su blog. Sus alegaciones son las siguientes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Primer ataque cibermilitar entre países. En concreto, el sabotaje de las &lt;a href="http://www.wired.com/threatlevel/2010/11/stuxnet-sabotage-centrifuges/"&gt;centrifugadoras de uranio enriquecido de Iran&lt;/a&gt; por parte del gusano informático&amp;nbsp;&lt;a href="http://es.wikipedia.org/wiki/Stuxnet"&gt;Stuxnet&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Organizaciones no gubernamentales beligerantes en la red. Como Wikileaks y sus filtraciones. El resultado ha sido la presión por parte de los EEUU a l&lt;a href="http://www.elmundo.es/elmundo/2010/12/06/internacional/1291654535.html"&gt;as empresas que gestionaban la financiación a esta organización&lt;/a&gt; (Visa, Mastercard, Paypal...)&lt;/li&gt;&lt;li&gt;Grupos de ciberataque como &lt;a href="http://es.wikipedia.org/wiki/Anonymous_(sociedad)"&gt;Anonymous&lt;/a&gt; que, en represalia por los bloqueos arriba mencionados, &lt;a href="http://www.elmundo.es/elmundo/2010/12/08/internacional/1291821338.html"&gt;atacaron las empresas&lt;/a&gt; que los realizaron.&lt;/li&gt;&lt;li&gt;Ciberdisidentes perseguidos. En este caso &lt;a href="http://es.wikipedia.org/wiki/Julian_Assange"&gt;el propio fundador de Wikileaks&lt;/a&gt; con extrañas imputaciones en un oscuro caso de acoso sexual y &lt;a href="http://www.elmundo.es/elmundo/2010/12/17/internacional/1292589160.html"&gt;altas fianzas tras su detención&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Los computadores empiezan a ver. Hasta ahora una imagen era únicamente una amalgama de píxeles de los cuales era difícil que el ordenador entendiera algo. A partir de la aparición de &lt;a href="http://www.xbox.com/es-ES/Xbox360/Accessories/kinect/Home"&gt;Kinect&lt;/a&gt; y su mapa de profundidad, el ordenador no sólo mira sino que también ve y entiende lo que ve. Además, &lt;a href="http://www.genbeta.com/actualidad/kinect-ya-ha-sido-hackeado"&gt;hackeado por un español&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Incremento exponencial del cibercrimen. En concreto, en 2010 se ha creado el &lt;a href="http://www.elmundo.es/elmundo/2011/01/03/navegante/1294054775.html"&gt;34% de todo el malware jamás creado&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lambiek.net/artists/s/shirow_masamune/shirow_ghost.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lambiek.net/artists/s/shirow_masamune/shirow_ghost.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Y tú que opinas, ¿somos ya ciberpunks o no?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-439024405404343981?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/439024405404343981/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/01/2010-el-primer-ano-ciberpunk-de-la.html#comment-form' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/439024405404343981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/439024405404343981'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2011/01/2010-el-primer-ano-ciberpunk-de-la.html' title='2010, el primer año ciberpunk de la historia'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-8995663127895656276</id><published>2010-12-26T17:56:00.000+01:00</published><updated>2010-12-26T17:56:00.161+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teoría de la información'/><title type='text'>Por qué no existe el compresor perfecto o los nidos de las palomas</title><content type='html'>Supongamos que existe un compresor que toma cualquier cadena de bits y la comprime en otra cadena con menos bits. Llamaremos [$c(x)$] al algoritmo compresor y [$d(x)$] al descompresor.&lt;br /&gt;&lt;br /&gt;Está claro que&lt;br /&gt;&lt;br /&gt;[$$c(0)=\epsilon$$]&lt;br /&gt;&lt;br /&gt;Puesto que la cadena vacía [$\epsilon$] es la única cadena con menos longitud que la cadena [$0$]. ¡Pero también es inmediato para la cadena [$1$]!&lt;br /&gt;&lt;br /&gt;[$$c(1)=\epsilon$$]&lt;br /&gt;&lt;br /&gt;Entonces, ¿cuánto es [$ d(\epsilon) $]? Porque sólo podrá ser una de las dos cadenas iniciales, pero no las dos.&lt;br /&gt;&lt;br /&gt;Esto es el llamado &lt;a href="http://es.wikipedia.org/wiki/Principio_del_palomar"&gt;principio del palomar&lt;/a&gt;. Sólo tenemos una cadena de longitud cero para almacenar dos cadenas de longitud uno. Si en un palomar hay más pichones que nidos, en algún nido habrá dos pichones (y no podremos descomprimirlos).&lt;br /&gt;&lt;br /&gt;Por tanto, no existe el compresor perfecto. Habrá cadenas que comprima y otras que expanda. El truco está en que comprima las cadenas más usadas y expanda las menos usadas.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-8995663127895656276?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/8995663127895656276/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2010/12/por-que-no-existe-el-compresor-perfecto.html#comment-form' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/8995663127895656276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/8995663127895656276'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2010/12/por-que-no-existe-el-compresor-perfecto.html' title='Por qué no existe el compresor perfecto o los nidos de las palomas'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-2349131278763788941</id><published>2010-12-20T13:25:00.000+01:00</published><updated>2010-12-20T13:25:00.375+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='miniSL'/><title type='text'>miniSL parte 7 - Las cadenas internas</title><content type='html'>El intérprete que estamos desarrollando es un intérprete basado en entornos. Esto quiere decir que cuando encontremos una variable y queramos saber su valor, vamos a buscar el nombre de la variable en el entorno actual. El entorno será un diccionario (std::map) de forma que habrá que comparar las cadenas del nombre de la variable y las claves almacenadas en el diccionario.&lt;br /&gt;&lt;br /&gt;Comparar cadenas es un algoritmo de complejidad O(n) lo que significa que va a ralentizar todo el proceso. Para solucionar esto la estrategia más común es usar lo que se llaman cadenas internas (&lt;a href="http://en.wikipedia.org/wiki/String_interning"&gt;interned string&lt;/a&gt;). De cada cadena interna sólo va a haber una única copia de forma que podamos usar su dirección para comparar cadenas. Así que la comparación de cadenas se reduce a una comparación de punteros.&lt;br /&gt;&lt;br /&gt;Para convertir una cadena a su cadena interna bastará buscar la copia única o, si no existe aún, crearla.&lt;br /&gt;STRING_MAP es el diccionario que a cada cadena le asigna una única copia. Esta copia será una celda del tipo NAME_CODE. De hecho, la única diferencia entre NAME_CODE y STRING_VAL es que en el primer caso la cadena es interna y en el segundo no (puede haber copias).&lt;br /&gt;&lt;br /&gt;ENVIR_TABLE es ahora la tabla de símbolos que relaciona un NAME_CODE (el nombre de la variable) con un valor. Cada entorno tendrá un ENVIR_TABLE y un puntero opcional al entorno padre.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;La clase Script, que contendrá todo el estado del intérprete del lenguaje que estamos creando, también tendrá que guardar el diccionario de cadenas internas. Lo haremos con la siguiente declaración de variable miembro privada.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;STRING_MAP m_InternedStrings;&lt;/pre&gt;&lt;br /&gt;Los casos de uso serán buscar o crear una cadena interna y borrarla. El valor de la cadena es accesible mediante CELL::string_val.&lt;br /&gt;&lt;br /&gt;La creación es algo más compleja que la destrucción ya que hemos de comprobar si ya está la cadena en nuestro diccionario.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;CELL&amp;amp; Script::CreateName(STRING const&amp;amp; val)&lt;br /&gt;{&lt;br /&gt; STRING_MAP::const_iterator i=m_InternedStrings.find(val);&lt;br /&gt; if(i==m_InternedStrings.end())&lt;br /&gt; {&lt;br /&gt;  CELL&amp;amp; c=CreateCell(NAME_CODE);&lt;br /&gt;  i=m_InternedStrings.insert(std::make_pair(val, &amp;amp;c)).first;&lt;br /&gt;  c.string_val=&amp;amp;i-&amp;gt;first;&lt;br /&gt; }&lt;br /&gt; return *i-&amp;gt;second;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Aprovechamos que la implementación de std::map es un árbol (y no mueve los nodos por memoria una vez creados) para usar la propia cadena que hace de clave como la única copia de la cadena. Por esa razón hacemos c.string_val=&amp;amp;i-&amp;gt;first. Esto no podría hacerse si la implementación fuera una tabla hash ya que estas tablas cambian de tamaño y requieren cambiar de posición de memoria las claves.&lt;br /&gt;&lt;br /&gt;La destrucción, por otro lado, es sencilla.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;m_InternedStrings.erase(*i-&amp;gt;string_val);&lt;/pre&gt;&lt;br /&gt;Aunque hay que ver esta línea en el contexto del recolector de basura. Dedicaremos la siguiente entrada a implementar el recolector de basura.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1486787303054252615-2349131278763788941?l=elmanantialdebits.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://elmanantialdebits.blogspot.com/feeds/2349131278763788941/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://elmanantialdebits.blogspot.com/2010/12/minisl-parte-7-las-cadenas-internas.html#comment-form' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/2349131278763788941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1486787303054252615/posts/default/2349131278763788941'/><link rel='alternate' type='text/html' href='http://elmanantialdebits.blogspot.com/2010/12/minisl-parte-7-las-cadenas-internas.html' title='miniSL parte 7 - Las cadenas internas'/><author><name>Gadelan</name><uri>http://www.blogger.com/profile/15307134297767374666</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1486787303054252615.post-1984313511660267762</id><published>2010-12-08T19:26:00.074+01:00</published><updated>2010-12-08T19:26:00.126+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='teoria de tipos'/><category scheme='http://www.blogger.com/atom/ns#' term='programación genérica'/><category scheme='http://www.blogger.com/atom/ns#' term='macros'/><title type='text'>C++: Conceptos y traits</title><content type='html'>Toda esta entrada es una especie de resumen personal de la presentación de &lt;a href="http://bartoszmilewski.wordpress.com/2010/11/29/understanding-c-concepts-through-haskell-type-classes/"&gt;Bartosz Milewski que podéis ver aquí&lt;/a&gt; más algunas ideas extra de mi propia cosecha.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="color: red;"&gt;&lt;span style="font-family: &amp;quot;Arial&amp;quot;, &amp;quot;Helvetica&amp;quot;, sans-serif;"&gt;&lt;span style="font-size: large;"&gt;Conceptos mediante traits&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Antes de nada hay que entender que los &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;template&lt;/span&gt; en C++ &lt;a href="http://elmanantialdebits.blogspot.com/2010/12/expresiones-dependientes-en-templates.html"&gt;no pueden compilarse inmediatamente &lt;/a&gt;porque no sabemos los tipos que vamos a tener cuando instanciemos el &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;template&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;El problema podría ser resuelto si forzamos a que estos tipos cumplan un contrato, una interfaz. La idea es hacerlo mediante los llamados &lt;a href="http://en.wikipedia.org/wiki/Concepts_(C%2B%2B)"&gt;conceptos&lt;/a&gt;. Por ejemplo, un tipo sobre el que podamos comprobar la igualdad, tendría un concepto parecido a este:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;concept Eq&amp;lt;T&amp;gt;&lt;br /&gt;{&lt;br /&gt; bool operator==(T const&amp;amp; l, T const&amp;amp; r);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ahora podríamos agregar tipos que cumplen ese concepto mediante lo que se denomina una asignación de concepto (&lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;concept_map&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;concept_map Eq&amp;lt;int&amp;gt;&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;bool operator==(int const&amp;amp; l, int const&amp;amp; r) { return l==r; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Hay que notar que el == de los enteros no es inmediatamente &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;Eq&lt;/span&gt; ya que el concepto  &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;Eq&lt;/span&gt; podría significar algo más que "tiene igual". Podría significar "tiene igual y es reflexivo, simétrico y transitivo" por lo que sólo el programador sabe si puede o no hacer un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;concept_map&lt;/span&gt; en función de la semántica del concepto.&lt;br /&gt;&lt;br /&gt;La idea es que ahora, en un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;template&lt;/span&gt;, se pueda usar el igual del concepto en vez del igual de la clausura dinámica.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:cpp"&gt;template&amp;lt;Eq T&amp;gt;&lt;br /&gt;T f(T const&amp;amp; a, T const&amp;amp; b)&lt;br /&gt;{&lt;br /&gt; return a==b ? a : b;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;El == este sería el del concepto &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;Eq&lt;/span&gt; y no una función que haya que esperar a tener el tipo &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;T&lt;/span&gt; para encontrarla en tiempo de instanciación. Por tanto, este &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;template&lt;/span&gt; se podría comprobar estáticamente en declaración. Sin saber si &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;T&lt;/span&gt; es un &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;int&lt;/span&gt; u otra cosa.&lt;br /&gt;&lt;br /&gt;La manera de implementar algo parecido en el C++ actual (aunque sin la ventaja de la comprobación en declaración) es mediante el uso de  &lt;a href="http://en.wikipedia.org/wiki/Trait_(computer_science)"&gt;traits&lt;/a&gt;. En vez de tener &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;Eq&lt;/span&gt; como un concepto (ya que el C++ actual carece de ellos) lo tendremos como una clase &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;Courier&amp;quot;, monospace;"&gt;Eq&amp;lt;T&amp;gt;&lt;/span&gt; que significa "el tipo &lt;span style="font-family: &amp;quot;Courier New&amp;quot;, &amp;quot;
