{"id":1578,"date":"2023-12-12T14:47:05","date_gmt":"2023-12-12T13:47:05","guid":{"rendered":"https:\/\/intsight.com\/?p=1578"},"modified":"2024-03-12T14:28:31","modified_gmt":"2024-03-12T13:28:31","slug":"unfold","status":"publish","type":"post","link":"https:\/\/intsight.com\/index.php\/2023\/12\/12\/unfold\/","title":{"rendered":"Unfold"},"content":{"rendered":"<p><span style=\"font-variant: small-caps; font-size: 107%\">\u00bfC\u00f3mo puedo calcular<\/span> la serie de Fibonacci en Austra, utilizando una secuencia? Con vectores (voy a usar vectores y secuencias reales para evitar problemas de desbordamiento), es relativamente sencillo, si aprovechamos los <a href=\"https:\/\/intsight.com\/index.php\/2023\/08\/03\/__trashed\/\" rel=\"noopener\" target=\"_blank\">safe indexers<\/a> en una expresi\u00f3n lambda:<\/p>\n<pre class=\"EnlighterJSRAW\">\nvec::new(128, (i, v) =>\n  if i = 0 then 1 else v{i-1} + v{i-2})\n<\/pre>\n<p>El problema de esta soluci\u00f3n es que consume memoria. Tenemos los dos \u00faltimos n\u00fameros generados a la izquierda (por as\u00ed decirlo) del n\u00famero que estamos generando, pero en realidad, es porque tenemos todo la memoria del vector ya reservada. \u00bfY si quisi\u00e9ramos hacerlo con las nuevas secuencias?<\/p>\n<h4>La soluci\u00f3n en lenguajes funcionales<\/h4>\n<p>Los lenguajes funcionales suelen usar una funci\u00f3n <code>unfold<\/code> para estos casos. Por ejemplo, en F# se define <code>unfold<\/code> de esta manera:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-linenumbers=\"false\" data-enlighter-language=\"F#\">\nval unfold : ('State -> ('T * 'State) option) -> 'State -> seq<'T>\n<\/pre>\n<p>La funci\u00f3n, en s\u00ed, escrita como una secuencia infinita, ser\u00eda m\u00e1s o menos esto.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-linenumbers=\"false\" data-enlighter-language=\"F#\">\nlet fib = Seq.unfold (fun (lastValue, currentValue)\n    -> Some (lastValue,\n    (currentValue, lastValue + currentValue))) (1, 1)\n<\/pre>\n<p>Ahora, las explicaciones: necesitar\u00edamos que Austra fuese un lenguaje con tipos gen\u00e9ricos e inferencia autom\u00e1tica de tipos&#8230; y no es un objetivo m\u00edo a corto plazo. Nyx, que es una idea de lenguaje con capacidades num\u00e9ricas y aceleraci\u00f3n que me guardo bajo la manga, tendr\u00e1 genericidad, pero no estoy del todo convencido que tenga que ser funcional \u00abpuro\u00bb.  La funci\u00f3n en F#, que ser\u00eda casi id\u00e9ntica en Haskell, necesita un \u00abestado\u00bb para ir arrastrando en las sucesivas llamadas. En el caso de Fibonacci, el estado son los \u00faltimos dos n\u00fameros generados.<\/p>\n<h4>De regreso a Austra<\/h4>\n<p>No obstante, podemos hacer algo \u00fatil para el 99% de los casos. Estos son los tres m\u00e9todos que se han implementado en C# para soportar <code>unfold<\/code> en el lenguaje de f\u00f3rmulas:<\/p>\n<pre class=\"EnlighterJSRAW\">\npublic static DSequence Unfold(int size,\n  double seed,\n  Func&lt;double, double&gt; unfold);\npublic static DSequence Unfold(int size,\n  double seed,\n  Func&lt;int, double, double&gt; unfold);\npublic static DSequence Unfold(int size,\n  double first, double second,\n  Func&lt;double, double, double&gt; unfold);\n<\/pre>\n<p>La idea es proporcionar sobrecargas para los casos m\u00e1s frecuentes. El primer caso es para cuando el estado es un solo n\u00famero real. El segundo caso es m\u00e1s sutil: el estado es un n\u00famero real&#8230; m\u00e1s la posici\u00f3n del elemento que se va a generar. Si estuvi\u00e9semos en un lenguaje funcional, esa posici\u00f3n tendr\u00eda que estar expl\u00edcitamente representada en el estado. Y en el tercer caso, el estado son dos n\u00fameros reales, como necesitamos para la secuencia de Fibonacci.<\/p>\n<p>Veamos ahora c\u00f3mo se usa esto en el lenguaje de f\u00f3rmulas:<\/p>\n<pre class=\"EnlighterJSRAW\">\n-- Potencias de 2, desde 2 a 1024.\nseq::unfold(10, 2, x => 2x);\n-- Serie de Maclaurin para exp(1).\n1 + seq::unfold(100000, 1, (n, x) => x \/ (n + 1)).sum;\n<\/pre>\n<p>He tenido que sumar expl\u00edcitamente un uno a la serie de Maclaurin, porque era lo m\u00e1s sencillo. Si quiere practicar, piense en c\u00f3mo calcular <code>ln(2)<\/code> con una secuencia de estas.<\/p>\n<p>La secuencia de Fibonacci se calcula as\u00ed:<\/p>\n<pre class=\"EnlighterJSRAW\">\nseq::unfold(50, 1, 1, (x, y) => x + y);\n<\/pre>\n<p>Con n\u00fameros enteros, har\u00edamos esto:<\/p>\n<pre class=\"EnlighterJSRAW\">\niseq::unfold(30, 1, 1, (x, y) => x + y);\n<\/pre>\n<p>No es la soluci\u00f3n perfecta, pero es f\u00e1cil de entender, y encima se ejecuta con rapidez.<\/p>\n<blockquote style=\"font-size:85%\"><p>Algo curioso relacionado con el dise\u00f1o de lenguajes: imagine un lenguaje que ofrece un <em>vec&lt;double&gt;<\/em> y un <em>vec&lt;complex&gt;<\/em>, en vez del <em>vec<\/em> y el <em>cvec<\/em> del lenguaje de f\u00f3rmulas de Austra. \u00bfSe ha dado cuenta de que el vector de complejos no podr\u00eda soportar todas las operaciones del vector de n\u00fameros reales? El caso m\u00e1s evidente: no se puede ordenar el vector de complejos, ni calcular la entrada con el menor o mayor valor. Los n\u00fameros complejos no soportan un orden total que tenga sentido. \u00bfC\u00f3mo har\u00eda usted para que una clase gen\u00e9rica tuviese en cuenta estos detalles? Ahora mismo, si quieres hacer esto en C#, tienes que definir una clase gen\u00e9rica \u00abrecortada\u00bb, en plan <em>Vec&lt;T&gt;<\/em>, y las clases finales ser\u00e1n clases que ya no ser\u00e1n gen\u00e9ricas, pero que a\u00f1adir\u00edan la funcionalidad no com\u00fan. Algo as\u00ed es que lo hace <a href=\"https:\/\/numerics.mathdotnet.com\/\" rel=\"noopener\" target=\"_blank\">Math.NET<\/a>.<\/p>\n<p>Ese es el problema que intento resolver: un lenguaje de programaci\u00f3n con auto-vectorizaci\u00f3n, en el que programar una librer\u00eda como la de Austra no sea tan complicado, y que me deje definir tipos matem\u00e1ticos como el vector de complejos y el vector de reales utilizando una base com\u00fan gen\u00e9rica. Hay m\u00e1s cosas en las matem\u00e1ticas que no se ajustan a la idea de la programaci\u00f3n de que \u00ablo derivado tiene m\u00e1s operaciones\u00bb.<\/p><\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>\u00bfC\u00f3mo puedo calcular la serie de Fibonacci en Austra, utilizando una secuencia? Con vectores (voy a usar vectores y secuencias reales para evitar problemas de desbordamiento), es relativamente sencillo, si aprovechamos los safe indexers en una expresi\u00f3n lambda: vec::new(128, (i, v) => if i = 0 then 1 else v{i-1} + v{i-2}) El problema de [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1596,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[92],"tags":[94,95,97,93,96],"class_list":["post-1578","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-austra","tag-f","tag-haskell","tag-maclaurin","tag-sequences","tag-unfold"],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/intsight.com\/wp-content\/uploads\/2023\/12\/unfld.png?fit=450%2C450&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/posts\/1578","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/comments?post=1578"}],"version-history":[{"count":17,"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/posts\/1578\/revisions"}],"predecessor-version":[{"id":1708,"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/posts\/1578\/revisions\/1708"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/media\/1596"}],"wp:attachment":[{"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/media?parent=1578"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/categories?post=1578"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/tags?post=1578"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}