{"id":1632,"date":"2024-01-09T19:17:50","date_gmt":"2024-01-09T18:17:50","guid":{"rendered":"https:\/\/intsight.com\/?p=1632"},"modified":"2024-01-09T19:18:31","modified_gmt":"2024-01-09T18:18:31","slug":"funciones-definidas-por-el-usuario","status":"publish","type":"post","link":"https:\/\/intsight.com\/index.php\/2024\/01\/09\/funciones-definidas-por-el-usuario\/","title":{"rendered":"Funciones definidas por el usuario"},"content":{"rendered":"<p><span style=\"font-variant: small-caps; font-size: 107%\">Vamos al grano, o<\/span>, como dir\u00eda Haskell B. Curry, \u00ablet&#8217;s cut to the chase\u00bb. Esto ya se puede hacer en AUSTRA (en cuanto libere la pr\u00f3xima versi\u00f3n):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-linenumbers=\"false\">\nlet mcd(a, b: int): int =\n    let m = a % b in iff(m = 0, b, mcd(b, m)) in\n        mcd(80, 140)\n<\/pre>\n<p>Esta es una versi\u00f3n recursiva del m\u00e1ximo com\u00fan divisor, calculado no con restas, sino con el m\u00f3dulo de la divisi\u00f3n. Observaciones importantes:<\/p>\n<ul type=\"bullet\">\n<li>Estoy declarando la funci\u00f3n como una funci\u00f3n local del script. Me falta permitir ahora la declaraci\u00f3n de funciones como si fuesen definiciones param\u00e9tricas. No lo he hecho todav\u00eda porque la implementaci\u00f3n de este tipo de funciones se realiza mediante lambdas, que se asignan a una variable local. La recursividad es posible porque la variable local est\u00e1 disponible, con toda la gloria de su prototipo, cuando se compila el cuerpo de la funci\u00f3n. Cuando se trate de una definici\u00f3n, probablemente use un truco parecido, pero no es tan inmediato (internamente) como cuando defino una funci\u00f3n como parte de una cl\u00e1usula <strong>let<\/strong>.<\/li>\n<li>Como se trata de una funci\u00f3n recursiva, observe que he definido su tipo de retorno expl\u00edcitamente. Si no, cuando el compilador encuentre la llamada recursiva a <em>mcd<\/em> va a tener que volverse loco infiriendo cu\u00e1l es el tipo de retorno. Ese tipo de inferencias es posible, pero ahora mismo el compilador no est\u00e1 preparado para ello. En mi defensa, recuerde que incluso el gran F# necesita el modificador <strong>rec<\/strong> para declarar funciones recursivas. Y F# s\u00ed es un lenguaje funcional con todas las de la ley.<\/li>\n<li>En este caso, hay una cl\u00e1usula <strong>let<\/strong> anidada dentro de la definici\u00f3n de funci\u00f3n. Austra ten\u00eda una regla para \u00abaplanar\u00bb siempre estas cl\u00e1usulas en el nivel superior, pero aqu\u00ed me interesa violar la regla. Eso, o tengo que calcular dos veces el m\u00f3dulo de los dos par\u00e1metros.<\/li>\n<\/ul>\n<p>Otro ejemplo de funci\u00f3n recursiva, que utiliza tambi\u00e9n una cl\u00e1usula <strong>let<\/strong> anidada, aunque esta vez, de tipo diferente:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-linenumbers=\"false\">\nlet fact(n: int) =\n    let f(n, acc: int): int = iff(n <= 1, acc, f(n - 1, n * acc)) in\n        f(n, 1);\nfact(10);\n<\/pre>\n<ul type=\"bullet\">\n<li>Esta es la archifamosa funci\u00f3n factorial, pero en vez de definirla en la forma m\u00e1s simple, la defino con una funci\u00f3n auxiliar que permite recursividad \"por la cola\".<\/li>\n<li>Aunque el factorial es normalmente recursivo, esta vez no se llama a s\u00ed mismo, y no hay que declarar expl\u00edcitamente el tipo de retorno.<\/li>\n<li>Por el contrario, la funci\u00f3n interna <em>f<\/em> s\u00ed se llama a s\u00ed misma, y hay que tener cuidado con su prototipo.<\/li>\n<\/ul>\n<p>Claro est\u00e1 que podemos declarar funciones sin tanta fanfarria. Por ejemplo, el factorial es mejor programarlo as\u00ed:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-linenumbers=\"false\">\nlet fact(n: int) = [x in 2..n].prod;\nfact(10);\n<\/pre>\n<p>Recuerde que empezamos con una secuencia de enteros, disfrazada de constructor de secuencias, por lo que no necesitamos poner los valores de la secuencia en un vector, ocupando memoria.<\/p>\n<p>Por cierto, mire lo que podemos hacer ahora con las secuencias:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-linenumbers=\"false\">\nlet collatz(n: int) =\n    iseq::unfold(1000000, n, x => iff(x % 2 = 0, x \/ 2, 3x + 1))\n    .until(x => x = 1);\ncollatz(137)\n<\/pre>\n<p>Esta funci\u00f3n genera la secuencia de la <a href=\"https:\/\/en.wikipedia.org\/wiki\/Collatz_conjecture\" rel=\"noopener\" target=\"_blank\">conjetura de Collatz<\/a> para el n\u00famero entero suministrado como par\u00e1metro. Es un problema interesante, y aparentemente f\u00e1cil, pero que a\u00fan no est\u00e1 resuelto. La novedad es que ahora Austra tiene un m\u00e9todo <a href=\"https:\/\/marteens.com\/austra\/library\/html\/ca2dc7c5-6c93-c1aa-5413-7abd140e0726.htm\" rel=\"noopener\" target=\"_blank\">Until<\/a> y un m\u00e9todo <a href=\"https:\/\/marteens.com\/austra\/library\/html\/720010c0-cb3a-ccc8-fac4-e0cfc9ac778e.htm\" rel=\"noopener\" target=\"_blank\">While<\/a> que sirven para este tipo de acrobacias. Nuestra funci\u00f3n <em>mcd<\/em> podr\u00eda haberse tambi\u00e9n programado sin recursi\u00f3n, mezclando <em>unfold<\/em> con uno de estos m\u00e9todos.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Vamos al grano, o, como dir\u00eda Haskell B. Curry, \u00ablet&#8217;s cut to the chase\u00bb. Esto ya se puede hacer en AUSTRA (en cuanto libere la pr\u00f3xima versi\u00f3n): let mcd(a, b: int): int = let m = a % b in iff(m = 0, b, mcd(b, m)) in mcd(80, 140) Esta es una versi\u00f3n recursiva del [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1631,"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":[73,90,91,103,96],"class_list":["post-1632","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-austra","tag-austra","tag-functional-programming","tag-lambda","tag-recursion","tag-unfold"],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/intsight.com\/wp-content\/uploads\/2024\/01\/rabbit.png?fit=500%2C500&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/posts\/1632","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=1632"}],"version-history":[{"count":8,"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/posts\/1632\/revisions"}],"predecessor-version":[{"id":1640,"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/posts\/1632\/revisions\/1640"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/media\/1631"}],"wp:attachment":[{"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/media?parent=1632"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/categories?post=1632"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/intsight.com\/index.php\/wp-json\/wp\/v2\/tags?post=1632"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}