Commits

Miguel Gordian committed 7bade19

Traducción: Funciones

Se completo la traducción del tema funciones del tour de Ceylon.

Se procede a confirmar los cambios para su posterior corrección
ortográfica y semántica.

Comments (0)

Files changed (1)

source/funciones.rst

+=========
+Funciones
+=========
+
+Esta el onceaba parte del tour de ceylon. En la parada anteior anterior
+hemos visto acerca de los paquetes y los modulos. Esta parada
+cubre los temas de clases de primero orden y de orden superior.
+
+------------------------------------------
+Clases de primer orden y de orden superior
+------------------------------------------
+
+Ceylon no es un lenguaje de programación funcional: debido a que tiene metodos
+que pueden tener efectos secundarios.Pero tiene algo en comun con los lenguajes
+de programación funcional y es que permiten tratar a las funcioones como 
+valores, lo cual a los ojos de algunas personas hace del lenguaje algun
+tipo de hibrido.
+En verdad, esto de tratar funciones como valores en un lenguaje orientado
+a obejtos no tiene nada nuevo, por ejemplo, Smalltalk es uno de los
+primeros  y aun uno de los lenguajes de programación de objetos mas puro,
+fue construido en torno a esta idea. De cualquier manera, Ceylon, como 
+smalltalk y un numero de otros lenguajes orientados a objetos, permite
+pasar a una función como un objeto y llevarlo a través del sistema.
+
+En esta parte, hablaremos acerca del soporte de Ceylon para funciones de
+primer orden y de orden superior.
+
+- El soporte a clases de primer orden significa la habilidad de tratar a 
+  funciones como valores, asignarla a variables y pasarlas como argmuento.
+- Una funcion de orden superior es una función que acepta funciones como
+  argumentos o devuelve una función.
+
+Esta claro que estas dos ideas van de la mano, asi que usaremos el termino
+"funciones de orden superior" desde ahora en adelante.
+
+
+-----------------------------------
+Representado el tipo de una función
+-----------------------------------
+
+Ceylon es un lenguaje fuertemente tipado. Asi que si vamos a tratar a 
+las funciones como valores, la primera pregunta a contestar es: ¿Cuál
+es el tipo de una función? Necesitamas una manera de representar el tipo
+de retorno y los tipos de los parametros de una funcion dentro del
+sistema de tipos.
+
+Recuerda que Ceylon, no tiene tipos de datos "primitivos". Un principio solido
+del diseño  es que cada tipo debera ser representado dentro del sistema 
+de tipos como una declación de una clase o una interfaz.
+
+En Ceylon, un simple tipo ``Callable`` abstrae todas las funciones. Su 
+declaración es la siguiente:
+
+.. code:: ceylon
+    
+    shared interface Callable<out Return, in Arguments>
+            given Arguments satisfies Anything[] {}
+
+El parametro de tipo ``Return`` representa el tipo de retorno de la función.
+El parametro de tipo secuencial ``Arguments``, debera ser una secuencia de 
+tipo, representa los tipos de los parametros de la función. Podemos representar
+una lista de parametros como un tipo tupla. Por ejemplo, la lista de
+parametros ``(String s, Float x)`` es representada  como la tupla 
+``[String, Float]``.
+
+Asi, que tomando la siguiente función:
+
+.. code:: ceylon
+    
+    function sum(Interger x, Integer y) => x+y;
+
+El tipo de la función ``sum()`` es:
+
+.. code:: ceylon
+    
+    Callabla<Integer,[Integer,Integer]>
+
+¿Qué hay acerca de las funciones ``void``? Bueno, El tipo de retorno de una
+función void es considerado a ser ``Anything``. Tal como el tipo de la
+función ``print()`` es:
+
+.. code:: ceylon
+    
+    Callable<Anything,[Anything]>
+
+
+Habra algunas personas que tienen un background en lenguajes como ML que
+talves esten esperando que ``void``  pueda ser identidicado con algun tipo
+"unit", por ejemplos, ``Null`` o talvez ``[]``. Pero este enfoque debera 
+significar que un metodo que no sea void debera no estar diponible 
+para refinar un metodo ``void`` y que una función que no sea de tipo void
+no estara disponible para ser asignado a un paramtro funcional ``void``.
+Sin embargo, codigo perfectamente razonable debera ser rechasado por el
+compilador.
+
+Note que una función ``void`` con una implementación concreta devuelve 
+implicitamente el valor ``null``. Esto es completamente diferente  a una
+función declarada a devolver el tipo ``Anything``, que puede devolver
+cualquier calor, pero debera hacerlo explicitamente, a través de la
+declaración ``return``. Las siguientes funciones tiene el mismo tipo,
+``Anything``, pero no hacen exactamente la misma cosa:
+
+.. code:: ceylon
+    
+    Anything hello() {
+        print("Hello")
+        return "hello";
+    }
+
+    void hello() {
+        print("hello");
+        //retorno implicito de null
+    }
+
+No deveras de confiar en una función que es declarada ``void``, debido a que
+puede ser un metodo que es refinado por una metodo no ``void`` o una 
+referencia a una función no ``void``.
+
+Podemos abreviar tipos ``Callable`` con un poco de azucar sintactica:
+
+- ``Integer(Integer,Integer)`` significa ``Callable<Integer,[Integer,Integer]>``
+
+  e igualmente,    
+
+- ``Anything(String)`` significa ``Callable<Anything,[String]>``.
+
+--------------------------------------
+Definiendo funciones de orden superior
+--------------------------------------
+
+Ahora tenemos suficiente conocimiento para poder escribir funciones de orden
+superior. Por ejemplo, podemos crear la función ``repeat()`` que ejecute
+repetidamente una función.
+
+.. code:: ceylon
+    
+    void repeat(Integer times,
+            Anything(Integer) perform) {
+        for (i in 1..times) {
+            perform(i);
+        }        
+    }
+
+Ahora, ejecutemos:
+
+.. code:: ceylon
+    
+    void printNum(Integer n) => print(n);
+    repeat(10, printNum);
+
+Esto debera de imprimir los numeros del 1 al 10 en consola.
+
+Existe un problema con esto. En Ceylon, como veremos despues, frecuentemenmente 
+llamamos funciones usando argumentos con nombre, pero el tipo ``Callable``
+no necesita codificar el nombre de los parametros de la función. Asi Ceylon tiene
+una alternativa, mas elegante, sintaxis para declarar un parametro de tipo ``Callable``:
+
+.. code:: ceylon
+    
+    void repeat(Integer timer,
+            void perform(Integer n) ) {
+        for (i in 1..times) {
+            perform { n=i; };
+        }        
+    }
+Esta versión es un poco mas legible, asi que el la sintaxis preferida.
+
+-----------------------
+Referencias a funciones
+-----------------------
+
+Cuando el nombre de una función aparece sin argumentos, como ``printNum``
+en el anterior ejercicio, es llamada una referencia a una función. Una 
+referencia a una función es el objeto que realmente es de tipo ``Callable``.
+En este caso, ``printNum`` tiene el tipo ``Callable<Anything,Integer>``.
+
+Ahora, ¿recuerdas como dijimos que ``Anything`` es el tipo de retorno de una
+función ``void`` y tambien la raiz de la herarquia de tipos? Bueno, esto es
+útil aqui, esto significa que podemos asignar una función de cualquier tipo
+a un parametro que espera una función de tipo ``void``, siempre y cuando
+coincidan las lista de parametros:
+
+.. code:: ceylon
+    
+    Boolean attemptPrint(Integer n) {
+        try {
+            print(n);
+            return true;
+        }
+        catch (Exception n) {
+            return false;
+        }
+    }
+
+Y podemos mandarla a llamar asi:
+
+.. code:: ceylon
+    
+    repeat(10, attemptPrint);
+
+Otra forma en la que podemos producir una referencia a una funcion es 
+por medio de aplicar parcialmente un metodo a una expresión (que recive).
+
+.. code:: ceylon
+    
+    class Hello(String name) {
+        shared void say(Integer n) {
+            print("Hello, ``name``, for the ``n``th time!");
+        }
+    }
+
+Y lo ejecutaremos de la siguiente manera:
+
+.. code:: ceylon
+
+    repeat(10, Hello("Gavin").say);
+
+En la expresión anterior ``Hello("Gavin").say`` tiene el mismo tipo que 
+``print``, es decir es de tipo ``Anything(Integer)``.
+
+-------
+Curring
+-------
+
+
+Un metodo o función puede ser declarado en una forma llamada ``curried``, 
+permitiendo  al metodo o función ser parcialmente aplicado a sus
+argumentos. Una función ``curried`` tiene multiples listas de parametros:
+
+.. code:: ceylon
+    
+    Float adder(Float x)(Float y) => x+y;
+
+La función ``adder()`` tiene el tipo ``Float(Float)(Float)``. Podemos 
+invocarla con un solo argumento para obtener la referencia a una función
+de tipo ``Float(Float)``, y mantener esta referencia como una función, 
+como esta:
+
+.. code:: ceylon
+    
+    Float addOne(Float y);
+    addOne = adder(1.0);
+
+O como un valor, como en el siguiente caso:
+
+.. code:: ceylon
+    
+    Float(Float) addOne = adder(1.0);
+
+(La unica diferencia entre estos dos enfoques es que en el primer caso
+le asignamos un nombre a el parametro de ``addOne()``.)
+
+Entonces subsecuentemente invocamos a ``addOne()``, el actual cuerpo de ``adder()``
+es finalmente ejecutado, produciendo un ``Float``.
+
+
+------------------
+Funciones anonimas
+------------------
+
+Las funciones mas famosas del estilo de orden superior son un trio de funciones
+que trasnforman, filtran, recoleccionan secuencias de calores. En Ceylon, estas tres
+funciones, ``map()``, ``filter()``, y ``fold()`` son metodos de la interfaz
+``Iterable``, (Incluso hay una cuarta, una amiga un poco menos glamurosa llamada
+``find()``, tambien un metodo de ``Iterable``.)
+
+Como probablemente habras notado todas las definiciones de funciones han sido declaradas
+con un nombre, usando la sintaxis tradicional estilo C. No hay nada errado con pasar 
+un numbre de una función a ``map()`` o ``filter()`` y de hecho es útil:
+
+.. code:: ceylon
+    
+    Float max = measurements.fold(0.0, largest<Float>);
+
+Sin embargo, comunmente, es un inconveniente tener que declarar una función dandole
+nombre completa solo para pasarselo a ``map()``, ``filter()``, ``fold()`` o 
+``find()``. En vez de ello, podemos declarar una función anonima,  como parte de la
+lista de argumentos.
+
+.. code:: ceylon
+    
+    Float max = measurements.fold(0.0, 
+                    (Float max, Float num) => 
+                        num > max then num  else max);
+
+                        
+Una función anonima consta de:
+
+- opcionalmente, la palabra ``function`` o ``void``
+- una lista de parametros, encerrados entre parentesis, seguidos por
+- una flecha gorda, =>, con una expresión o
+- un bloque.
+
+Asi que podemos reescribir lo anterior usando un bloque.
+
+.. code:: ceylon
+    
+    Float max = measurements.fold(0.0, 
+            (Float max, Float num) {
+                return num>max then num else max;
+            });
+
+Note que es un poco mas dificil dar una buena vista a las funciónes 
+anonimas con bloque, asi que usualmente es mejor darle el nombre 
+a una función y usarla como referencia.
+
+
+-----------------------------------------
+Mas acerca de funciones de orden superior
+-----------------------------------------
+    
+Veamos un ejemplo practico, que mezcle ambas maneras de representar el
+tipo de una función.
+
+Supongamos que tenemos algun tipo de interfaz de usuario que puede ser observado
+por objetos en el sistema. Podemos usar algo como el patron de Java 
+``Observer/Observable``:
+
+.. code:: ceylon
+    
+    interface Observer {
+        shared formal void observe(Event event);
+    }
+
+    abstract class Component() {
+        variable {Observer*} observers = {};
+
+        shared void addObserver(Observer observer) {
+            observers = {observer, *observers};
+        }
+
+        shared void fire(Event event) {
+            for (o in observers) {
+                o.observe(event);
+            }
+        }
+    }
+
+Pero ahora todos los objetos tienen que implementar la interfaz ``Observer``,
+que solo tiene un metodo. ¿Porqué no simplemente dejamos fuera a la interfaz
+y permitimos a los observadores de eventos solo registrar un objeto función
+como su evento de escucha? En el siguiente  código, definimos que el método
+``addObserver`` acepte una función como parametro.
+
+.. code:: ceylon
+    
+
+    abstract class Component() {
+        variable {Anything((Event)*} observers = {};
+
+        shared void addObserver(void observe(Event event)) {
+            observers = {observe, *observers};
+        }
+
+        shared void fire(Event event) {
+            for (observe in observers) {
+                observe(event);
+            }
+        }
+    }
+
+Aqui podemos ver la diferencia entre las dos maneras de especificar el 
+el tipo de una función:
+
+- ``void observe(Event event)`` es mas legible en lista de parametro,
+  donde ``observe`` es el nombre del parametro, pero
+- ``Anything(Event)`` es util en el tipo del contenedortal como un
+  iterable.
+
+ahora, cualquiere observador de evento puede solo pasar una referencia
+a uno de sus metodos a ``addObserver()``:
+
+.. code:: ceylon
+    
+    class Listener(Component component) {
+    
+        void onEvent(Event e){
+            //responde al evento
+            // ...
+        }
+
+        component.addObserver(onEvent);
+
+        // ...
+    }
+
+Cuando el nombre de el metodo aparece en una expresión sin una lista de 
+argumentos despues de el, es una referencia a un método, no una invocación
+al metodo. Aqui la expresión de tipo ``Anything(Event)`` que refiere al metodo
+``onEvent()``.
+
+Si ``onEvent()`` fuese ``shared``, podemos incluso hilar ``Component`` y ``Listener``
+desde algun otro codigo, para eliminar la dependencia de ``Listener`` sobre 
+``Component``.
+
+.. code:: ceylon
+    
+    class Listener() {
+
+        shared void onEvent() {
+            // respuesta a el evento
+            // ...
+        }
+    }
+
+    void listen(Component component, Listener listener) {
+        component.addObserver(listener.onEvent);
+    }
+
+Aqui la sintaxis de ``listener.onEvent()`` es un tipo de aplicación parcial
+del metodo  ``onEvent()``. Esto no causa que el método sea ejecutado(debido 
+a que no hemos provisto una lista de parametros aún). En vez, resulta en una 
+función que empaqueta juntos a el metodo referencia ``onEvent`` y el metodo
+recividor ``listener``.
+
+Es tambien posible declarar un metodo que devuelva una función. Vamos a 
+considerarla abilidad para remover observadores desde un ``Component``.
+Podemos usar una interfaz ``subscription``:
+
+.. code:: ceylon
+    
+    interface Subscription {
+       shared formal void cancel(); 
+    }
+
+    abstract class Component() {
+        variable {Anything(Event)*} observers = {};
+
+        shared Subscription addObserver(void observe(Event event)) {
+            observers = {observe,*observers};
+            object subscription satisfies Subscription {
+                cancel() => observers =
+                        { for (o in observers) if (o!=observe) o };
+            }
+            return subscription;
+        }
+    
+        shared void fire(Event event) {
+            for (observe in observers) {
+                observe(event);
+            }
+        }     
+   }
+
+Pero una solución simple puede ser solo eliminar la interfaz y devolver
+el método ``cancel()`` directamente:
+
+.. code:: ceylon
+    
+    
+    abstract class Component() {
+        variable {Anything(Event)*} observers = {};
+
+        shared Anything() addObserver(void observe(Event event)) {
+            observers = {observe,*observers};
+            return void () => observers =
+                        { for (o in observers) if (o!=observe) o };
+        }
+    
+        shared void fire(Event event) {
+            for (observe in observers) {
+                observe(event);
+            }
+        }     
+   }
+
+Aqui, hemos definido una función anonima dentro de el método ``addObserver()``, y
+retornar una referencia a esta función fuera del método. La refencia a la función
+anonima devuelta por ``addObserver()`` puede ser llamada por cualquier código que 
+obtenga la referencia..
+
+En caso que te estes preguntando el tipo de la función que se encuentra dentro del 
+método ``addObserver()`` es ``Anything()(Anything(Event)``.
+
+Note que la función anonima esta abilitada para usar el parametro ``observe`` de
+``addObserver()``. Diremos que el metodo anidado recive una ``closure`` de las no
+variable locales y parametros desde afuera del metodo - Justo como un metodo de una
+clase recive una ``closure`` de la clase inicializando parametros y locales de la
+clase inicializador. En general, cualquier declaración de clase anidad, método o 
+atributo siempre recive recive la ``closure`` de la declaración de los miembros de 
+la clase, método o atributo en que este es encerrado. Este es un ejemplo de que
+tan regular es el lenguaje.
+
+Podemos invocar nuestro método de la siguiente manera:
+
+.. code:: ceylon
+    
+    addObserver(onEvent)();
+
+Pero si estamos planeando usar el método de esta manera, problablemente no se 
+buena razon para darle dos listas de parametros. 
+Esto es mucho mas probable que cuando estabamos planeando mantener o pasar
+la referencia a el metodo anidado en algun lugar método antes de incocarlo.
+
+.. code:: ceylon
+    
+    Anthing() cancel = addObserver(onEvent);
+
+    //...
+    cancel();
+
+La primera linea demuestra como la referencia de una función  puede ser 
+mantenida. La segunda linea de codigo simplemente invoca la referencia
+devuelta a ``cancel()``.
+
+-------------------
+Composición y curry
+-------------------
+
+La función ``compose()`` lleva acaba **composición de funciones**. Por 
+ejemplo, dadas las funciones ``print()`` y ``plus()`` en ``ceylon.language``,
+con la siguiente forma:
+
+.. code:: ceylon
+    
+    shared void print(Anything line) { ... }
+
+    shared Value plus<Value>(Value x, Value y) { ... }
+
+Podemos ver que el tipo de referencia de la función ``print()`` es 
+``Anything(Anything)``, y el tipo de la referencia a la función 
+``plus<Float>`` es ``Float(Float, Float)``. Entonces podemos
+escribir lo siguiente:
+
+.. code:: ceylon
+    
+    Anything(Float, Float) printSum = compose(print,plus<Float>);
+    printSum(2.0,2.0); //imprime 4.0
+
+La función ``curry()`` produce una función con multiples listas
+de parametros, dada una función con multiples lista de parametros:
+
+.. code:: ceylon
+    
+    Anything(Float)(Float) printSumCurried = curry(printSum);
+    Anything(Float) printPlus2 = printSumCurried(2.0);
+    printPlus(2.0); //imprime 4.0
+
+
+La función ``uncurry()`` hace lo opuesto, dandonos la forma original.
+
+.. code:: ceylon
+    
+    Anything(Float,Float) printSumUncurried = uncurry(printSumCurried);
+
+Note que ``compose()``, ``curry`` y ``uncurry()`` son funciónes ordinarias
+escritas en Ceylon.
+
+
+------------------
+El operador spread
+------------------
+
+Ya hemos visto unos pocos ejemplos de el operador ``spread``. Hemos visto
+como usarlo para instaciar un iterable:
+
+.. code:: ceylon
+    
+    { "hello", *names }
+
+O una tupla:
+
+
+.. code:: ceylon
+    
+    [x, y, *labels]
+
+Tambien podemos usarlo cuando llamamos una función. Considere la
+siguiente función.
+
+.. code:: ceylon
+    
+    String formatDate(String format,
+                      Integer day,
+                      Integer|String month,
+                      Integer year) { 
+        ...
+   }
+
+Y supongase que tenemos una tupla representando una fecha:
+
+.. code:: ceylon
+    
+    value date = [15, "January", 2010];
+
+Entonces podemos pasar la fecha a nuestra función como 
+lo siguiente:
+
+.. code:: ceylon
+    
+    formatDate("dd MMMMMM yyyy", *date);
+
+Note que el tipo de la tupla ``["dd MMMMMM yyyy", *date]`` es:
+
+.. code:: ceylon
+    
+    [String,Integer,String,Integer]
+
+Ahora considerar el tipo de la función ``formatDate``:
+
+.. code:: ceylon
+    
+    String(String,Integer,Integer|String,Integer)
+
+o tambien:
+
+.. code:: ceylon
+    
+    Callable<String,[String,Integer,Integer|String,Integer]>
+
+Desde que la tupla tipo ``[String,Integer,String,Integer]`` es un 
+subtipo de ``[String,Integer,Integer|String,Integer]``, la invocación
+esta bien tipada. ¡Esto demuestra la relación  entre tuplas y argumentos
+de función!.
+
+-----------
+Aún hay más
+-----------
+
+Podrás encontrar una discución mas detallada de como Ceylon represente 
+tipos de funciones usando tuplas `aqui<http://ceylon-lang.org/blog/2013/01/21/abstracting-over-functions/>`
+incluyendo una discución a detalle de ``compose()`` y ``curry()``.
+
+Ahora es turno de la sintaxis para lista de argumentos con nombre y para
+definir interfaces de usuario e información estructurada.