En la progtwigción funcional, ¿qué es un funtor?

Me he topado con el término “Functor” varias veces mientras leo varios artículos sobre progtwigción funcional, pero los autores suelen suponer que el lector ya entiende el término. Mirar en la web ha proporcionado descripciones excesivamente técnicas (ver el artículo de Wikipedia ) o descripciones increíblemente vagas (ver la sección sobre Functors en este sitio web ocaml-tutorial ).

¿Alguien puede definir amablemente el término, explicar su uso y quizás proporcionar un ejemplo de cómo se crean y utilizan los Functors?

Editar : Si bien estoy interesado en la teoría detrás del término, estoy menos interesado en la teoría que en la implementación y el uso práctico del concepto.

Edición 2 : Parece que hay una terminología cruzada: me refiero específicamente a los Funcionadores de la progtwigción funcional, no a los objetos funcionales de C ++.

La palabra “functor” proviene de la teoría de categorías, que es una twig de las matemáticas muy general y muy abstracta. Ha sido tomado prestado por diseñadores de lenguajes funcionales en al menos dos formas diferentes.

  • En la familia de idiomas ML, un funtor es un módulo que toma uno o más módulos como parámetro. Se considera una función avanzada, y la mayoría de los progtwigdores principiantes tienen dificultades con ella.

    Como ejemplo de implementación y uso práctico, podría definir su forma favorita de árbol de búsqueda binaria equilibrada de una vez y para siempre como un funtor, y tomaría como parámetro un módulo que proporciona:

    • El tipo de clave que se utilizará en el árbol binario

    • Una función de ordenamiento total en las teclas

    Una vez que haya hecho esto, puede usar la misma implementación de árbol binario equilibrado para siempre. (El tipo de valor almacenado en el árbol generalmente se deja polimórfico; el árbol no necesita mirar valores más que copiarlos, mientras que el árbol definitivamente necesita poder comparar claves, y obtiene la función de comparación de el parámetro del funtor).

    Otra aplicación de los funtores ML es la de los protocolos de red . El enlace es a un documento realmente excelente del grupo CMU Fox; muestra cómo usar funtores para construir capas de protocolo más complejas (como TCP) en el tipo de capas más simples (como IP o incluso directamente sobre Ethernet). Cada capa se implementa como un funtor que toma como parámetro la capa debajo de él. La estructura del software realmente refleja la forma en que las personas piensan sobre el problema, a diferencia de las capas que existen solo en la mente del progtwigdor. En 1994, cuando se publicó este trabajo, fue un gran problema.

    Para ver un ejemplo salvaje de los funtores de ML en acción, se puede ver el documento ML Module Mania , que contiene un ejemplo publicable (es decir, aterrador) de funtores en acción. Para obtener una explicación shiny, clara y pellucida del sistema de módulos ML (con comparaciones con otros tipos de módulos), lea las primeras páginas del shiny documento POPL 1994 de Manuel, Manifest Types, Modules, and Separate Comstacktion, de Xavier Leroy.

  • En Haskell, y en algún lenguaje funcional puro relacionado, Functor es una clase de tipo . Un tipo pertenece a una clase de tipo (o más técnicamente, el tipo “es una instancia de” la clase de tipo) cuando el tipo proporciona ciertas operaciones con cierto comportamiento esperado. Un tipo T puede pertenecer a la clase Functor si tiene cierto comportamiento tipo colección:

    • El tipo T se parametriza sobre otro tipo, que debería considerar como el tipo de elemento de la colección. El tipo de la colección completa es algo así como T Int , T String , T Bool , si contiene enteros, cadenas o booleanos, respectivamente. Si el tipo de elemento es desconocido, se escribe como un parámetro de tipo a , como en T a .

      Los ejemplos incluyen listas (cero o más elementos del tipo a ), el tipo Maybe (cero o uno del tipo a ), conjuntos de elementos del tipo a , matrices de elementos del tipo a , todos los tipos de árboles de búsqueda que contienen valores del tipo a y muchos otros en los que puedes pensar

    • La otra propiedad que T debe cumplir es que si tiene una función de tipo a -> b (una función en elementos), entonces debe poder llevar esa función y producto a una función relacionada en las colecciones. Haga esto con el operador fmap , que es compartido por cada tipo en la clase de tipo Functor . El operador está realmente sobrecargado, por lo que si tiene una función even con tipo Int -> Bool , entonces

       fmap even 

      es una función sobrecargada que puede hacer muchas cosas maravillosas:

      • Convierta una lista de enteros a una lista de Booleanos

      • Convierta un árbol de enteros en un árbol de Booleanos

      • Convertir Nothing en Nothing y Just 7 en Just False

      En Haskell, esta propiedad se expresa dando el tipo de fmap :

       fmap :: (Functor t) => (a -> b) -> ta -> tb 

      donde ahora tenemos una pequeña t , que significa “cualquier tipo en la clase Functor “.

    Para fmap , en Haskell un functor es una especie de colección para la cual si se le asigna una función en los elementos, fmap le devolverá una función en las colecciones . Como se puede imaginar, esta es una idea que puede ser ampliamente reutilizada, por lo que es bendecida como parte de la biblioteca estándar de Haskell.

Como de costumbre, las personas siguen inventando abstracciones nuevas y útiles, y es posible que desee buscar funcionadores aplicativos , para lo cual la mejor referencia puede ser un documento llamado Progtwigción Aplicativa con Efectos de Conor McBride y Ross Paterson.

Otras respuestas aquí están completas, pero intentaré otra explicación del uso de FP de functor . Toma esto como una analogía:

Un functor es un contenedor de tipo a que, cuando se lo somete a una función que se asigna de ab , produce un contenedor de tipo b .

A diferencia del uso de puntero-función-abstraída en C ++, aquí el “functor” no es la función; más bien, es algo que se comporta de manera consistente cuando se lo somete a una función .

¡Hay tres significados diferentes, no muy relacionados!

  • En Ocaml es un módulo parametrizado. Ver el manual . Creo que la mejor manera de asimilarlos es por ejemplo: (escrito rápidamente, podría tener errores)

     module type Order = sig type t val compare: t -> t -> bool end;; module Integers = struct type t = int let compare xy = x > y end;; module ReverseOrder = functor (X: Order) -> struct type t = Xt let compare xy = X.compare yx end;; (* We can order reversely *) module K = ReverseOrder (Integers);; Integers.compare 3 4;; (* this is false *) K.compare 3 4;; (* this is true *) module LexicographicOrder = functor (X: Order) -> functor (Y: Order) -> struct type t = Xt * Yt let compare (a,b) (c,d) = if X.compare ac then true else if X.compare ca then false else Y.compare bd end;; (* compare lexicographically *) module X = LexicographicOrder (Integers) (Integers);; X.compare (2,3) (4,5);; module LinearSearch = functor (X: Order) -> struct type t = Xt array let find xk = 0 (* some boring code *) end;; module BinarySearch = functor (X: Order) -> struct type t = Xt array let find xk = 0 (* some boring code *) end;; (* linear search over arrays of integers *) module LS = LinearSearch (Integers);; LS.find [|1;2;3] 2;; (* binary search over arrays of pairs of integers, sorted lexicographically *) module BS = BinarySearch (LexicographicOrder (Integers) (Integers));; BS.find [|(2,3);(4,5)|] (2,3);; 

Ahora puede agregar rápidamente muchas órdenes posibles, maneras de formar nuevas órdenes, hacer una búsqueda binaria o lineal fácilmente sobre ellas. Progtwigción genérica FTW.

  • En lenguajes de progtwigción funcionales como Haskell, significa algunos constructores de tipos (tipos parametrizados como listas, conjuntos) que pueden “mapearse”. Para ser precisos, un funtor f está equipado con (a -> b) -> (fa -> fb) . Esto tiene orígenes en la teoría de categorías. El artículo de Wikipedia al que vinculó es este uso.

     class Functor f where fmap :: (a -> b) -> (fa -> fb) instance Functor [] where -- lists are a functor fmap = map instance Functor Maybe where -- Maybe is option in Haskell fmap f (Just x) = Just (fx) fmap f Nothing = Nothing fmap (+1) [2,3,4] -- this is [3,4,5] fmap (+1) (Just 5) -- this is Just 6 fmap (+1) Nothing -- this is Nothing 

Por lo tanto, este es un tipo especial de constructores de tipo, y tiene poco que ver con funtores en Ocaml.

  • En lenguajes imperativos, es un puntero a la función.

En OCaml, es un módulo parametrizado.

Si conoce C ++, piense en un functor OCaml como plantilla. C ++ solo tiene plantillas de clase, y los funtores funcionan en la escala del módulo.

Un ejemplo de functor es Map.Make; module StringMap = Map.Make (String);; construye un módulo de mapa que funciona con mapas de clave String.

No podría lograr algo como StringMap con solo polymorphism; necesitas hacer algunas suposiciones sobre las teclas. El módulo String contiene las operaciones (comparación, etc.) en un tipo de cadena totalmente ordenada, y el funtor se vinculará con las operaciones que contiene el módulo String. Podrías hacer algo similar con la progtwigción orientada a objetos, pero tendrías la sobrecarga indirecta del método.

Tienes bastantes buenas respuestas. Voy a lanzar:

Un functor, en el sentido matemático, es un tipo especial de función en un álgebra. Es una función mínima que mapea un álgebra a otro álgebra. “Minimality” se expresa por las leyes de functor.

Hay dos maneras de ver esto. Por ejemplo, las listas son funtores sobre algún tipo. Es decir, dado un álgebra sobre un tipo ‘a’, puede generar un álgebra compatible de listas que contengan elementos del tipo ‘a’. (Por ejemplo: el mapa que lleva un elemento a una lista singleton que lo contiene: f (a) = [a]) Una vez más, la noción de compatibilidad está expresada por las leyes del funtor.

Por otro lado, dado un funtor f “sobre” un tipo a, (es decir, fa es el resultado de aplicar el funtor f al álgebra del tipo a), y funciona desde g: a -> b, podemos calcular un nuevo funtor F = (fmap g) que asigna fa a f b. En resumen, fmap es la parte de F que mapea “partes de functor” a “partes de functor”, y g es la parte de la función que mapea “partes de álgebra” a “partes de álgebra”. Toma una función, un functor, y una vez completo, ES un functor también.

Podría parecer que diferentes lenguajes utilizan diferentes nociones de funtores, pero no lo son. Simplemente usan funtores sobre diferentes álgebras. OCamls tiene un álgebra de módulos y los funtores sobre ese álgebra le permiten adjuntar nuevas declaraciones a un módulo de una manera “compatible”.

Un functor Haskell NO es una clase de tipo. Es un tipo de datos con una variable libre que satisface la clase de tipo. Si está dispuesto a excavar en las entrañas de un tipo de datos (sin variables libres), puede reinterpretar un tipo de datos como un funtor sobre un álgebra subyacente. Por ejemplo:

datos F = F Int.

es isomorfo para la clase de Ints. Entonces, F, como constructor de valor, es una función que mapea Int a F Int, un álgebra equivalente. Es un funtor. Por otro lado, no obtienes fmap gratis aquí. Para eso es la coincidencia de patrones.

Los funtores son buenos para “unir” cosas a elementos de álgebras, de una manera algebraicamente compatible.

Hay un ejemplo bastante bueno en el libro de O’Reilly OCaml que está en el sitio web de Inria (que a la fecha de escribir esto desafortunadamente no funciona). Encontré un ejemplo muy similar en este libro utilizado por caltech: Introducción a OCaml (enlace pdf) . La sección relevante es el capítulo sobre funtores (Página 139 en el libro, página 149 en el PDF).

En el libro tienen un functor llamado MakeSet que crea una estructura de datos que consiste en una lista y funciones para agregar un elemento, determinar si un elemento está en la lista y para encontrar el elemento. La función de comparación que se usa para determinar si está dentro / no en el conjunto ha sido parametrizada (que es lo que hace que MakeSet sea un functor en lugar de un módulo).

También tienen un módulo que implementa la función de comparación para que haga una comparación de cadena insensible a mayúsculas y minúsculas.

Usando el funtor y el módulo que implementa la comparación, pueden crear un nuevo módulo en una línea:

 module SSet = MakeSet(StringCaseEqual);; 

eso crea un módulo para una estructura de datos establecida que usa comparaciones insensibles a mayúsculas y minúsculas. Si quisiera crear un conjunto que utilizara comparaciones con distinción entre mayúsculas y minúsculas, entonces solo necesitaría implementar un nuevo módulo de comparación en lugar de un nuevo módulo de estructura de datos.

Tobu comparó los funtores con las plantillas en C ++, lo cual creo que es bastante apropiado.

La mejor respuesta a esa pregunta se encuentra en “Typeclassopedia” por Brent Yorgey.

Este número de Monad Reader contiene una definición precisa de lo que es un functor, así como muchas definiciones de otros conceptos, así como un diagtwig. (Monoid, Applicative, Monad y otro concepto se explican y se ven en relación con un functor).

http://haskell.org/sitewiki/images/8/85/TMR-Issue13.pdf

Extracto de Typeclassopedia for Functor: “Una intuición simple es que un Functor representa un” contenedor “de algún tipo, junto con la capacidad de aplicar una función uniformemente a cada elemento en el contenedor”

Pero realmente todo el typeclassopedia es una lectura altamente recomendada que es sorprendentemente fácil. En cierto modo, puede ver la clase de tipo presentada allí como un patrón de diseño paralelo en el objeto en el sentido de que le dan un vocabulario para un comportamiento o capacidad determinados.

Aclamaciones

Aquí hay un artículo sobre funtores de un POV de progtwigción , seguido más específicamente de cómo aparecen en los lenguajes de progtwigción .

El uso práctico de un functor está en una mónada, y puedes encontrar muchos tutoriales sobre mónadas si buscas eso.

Dadas las otras respuestas y lo que voy a publicar ahora, diría que es una palabra bastante sobrecargada, pero de todos modos …

Para obtener una pista sobre el significado de la palabra ‘functor’ en Haskell, pregúntale a GHCi:

 Prelude> :info Functor class Functor f where fmap :: forall a b. (a -> b) -> fa -> fb (GHC.Base.<$) :: forall a b. a -> fb -> fa -- Defined in GHC.Base instance Functor Maybe -- Defined in Data.Maybe instance Functor [] -- Defined in GHC.Base instance Functor IO -- Defined in GHC.Base 

Entonces, básicamente, un functor en Haskell es algo que puede mapearse. Otra forma de decirlo es que un functor es algo que se puede considerar como un contenedor al que se le puede pedir que use una función dada para transformar el valor que contiene; por lo tanto, para las listas, fmap coincide con el map , para Maybe , fmap f (Just x) = Just (fx) , fmap f Nothing = Nothing etc.

La subsección Tipo de clase de Functor y la sección sobre Functors, Applicative Functors y Monoids de Learn You a Haskell for Great Good dan algunos ejemplos de dónde este concepto particular es útil. (Un resumen: ¡muchos lugares! :-))

Tenga en cuenta que cualquier mónada puede tratarse como un funtor, y de hecho, como señala Craig Stuntz, los funtores utilizados con mayor frecuencia tienden a ser mónadas … OTOH, a veces es conveniente hacer que un tipo sea un ejemplo de la clase de tipo Functor. sin tomarse la molestia de convertirlo en una Mónada. (Por ejemplo, en el caso de ZipList from Control.Applicative , mencionado en una de las páginas antes mencionadas ).

En un comentario a la respuesta más votados, el usuario Wei Hu pregunta:

Entiendo tanto funtores de ML como funtores de Haskell, pero carezco de la comprensión necesaria para relacionarlos. ¿Cuál es la relación entre estos dos, en un sentido de categoría teórica?

Nota : No sé ML, así que por favor perdone y corrija cualquier error relacionado.

Supongamos inicialmente que todos estamos familiarizados con las definiciones de “categoría” y “functor”.

Una respuesta compacta sería que “Haskell-functors” son (endo-) funtores F : Hask -> Hask mientras que “ML-functors” son funtores G : ML -> ML' .

Aquí, Hask es la categoría formada por los tipos y funciones Haskell entre ellos, y de forma similar, ML y ML' son categorías definidas por estructuras ML.

Nota : Hay algunos problemas técnicos para hacer de Hask una categoría, pero hay formas de Hask .

Desde una perspectiva teórica de categoría, esto significa que un Hask -un_unctor es un mapa F de tipos Haskell:

 data F a = ... 

junto con un mapa fmap de las funciones de Haskell:

 instance Functor F where fmap f = ... 

ML es prácticamente lo mismo, aunque no fmap ninguna abstracción fmap canónica, así que vamos a definir una:

 signature FUNCTOR = sig type 'af val fmap: 'a -> 'b -> 'af -> 'bf end 

Eso es f maps ML -type y fmap maps ML -funciones, entonces

 functor StructB (StructA : SigA) :> FUNCTOR = struct fmap g = ... ... end 

es un funtor F: StructA -> StructB .

“Functor es un mapeo de objetos y morfismos que preserva la composición y la identidad de una categoría”.

Vamos a definir lo que es una categoría?

Es un montón de objetos!

Dibuja algunos puntos (por ahora 2 puntos, uno es ‘a’ otro es ‘b’) dentro de un círculo y nombra ese círculo A (Categoría) por ahora.

¿Qué contiene la categoría?

Composición entre objetos y función de identidad para cada objeto.

Entonces, tenemos que mapear los objetos y preservar la composición después de aplicar nuestro Functor.

Imaginemos que ‘A’ es nuestra categoría que tiene objetos [‘a’, ‘b’] y existe un morfismo a -> b

Ahora, tenemos que definir un functor que pueda mapear estos objetos y morfismos en otra categoría ‘B’.

Digamos que el functor se llama ‘Maybe’

 data Maybe a = Nothing | Just a 

Entonces, la categoría ‘B’ se ve así.

Dibuja otro círculo, pero esta vez con ‘Quizás un’ y ‘Quizás b’ en lugar de ‘a’ y ‘b’.

Todo parece bueno y todos los objetos están mapeados

“a” se convirtió en “Tal vez a” y “b” se convirtió en “Tal vez b”.

Pero el problema es que tenemos que mapear el morfismo de ‘a’ a ‘b’ también.

Eso significa que el morfismo a -> b en ‘A’ debería corresponderse con el morfismo ‘Tal vez’ -> ‘Quizás b’

el morfismo de a -> b se llama f, luego el morfismo de ‘Quizás a’ -> ‘Quizás b’ se llame ‘fmap f’

Ahora veamos qué función ‘f’ estaba haciendo en ‘A’ y veamos si podemos replicarlo en ‘B’

definición de función de ‘f’ en ‘A’:

 f :: a -> b 

f toma a y devuelve b

definición de función de ‘f’ en ‘B’:

 f :: Maybe a -> Maybe b 

f toma Maybe a y return Maybe b

veamos cómo usar fmap para mapear la función ‘f’ de ‘A’ para funcionar ‘fmap f’ en ‘B’

definición de fmap

 fmap :: (a -> b) -> (Maybe a -> Maybe b) fmap f Nothing = Nothing fmap f (Just x) = Just(fx) 

Entonces que hacemos aqui ?

Estamos aplicando la función ‘f’ a ‘x’, que es del tipo ‘a’. La coincidencia de patrones especiales de ‘Nothing’ proviene de la definición de Functor Maybe .

Entonces, asignamos nuestros objetos [a, b] y morfismos [f] de la categoría ‘A’ a la categoría ‘B’.

Eso es Functor!

enter image description here

No debe contradecir las respuestas teóricas o matemáticas anteriores, pero un Functor es también un Objeto (en un lenguaje de progtwigción orientado a objetos) que tiene un solo método y se usa efectivamente como una función.

Un ejemplo es la interfaz Runnable en Java, que tiene solo un método: ejecutar.

Considere este ejemplo, primero en Javascript, que tiene funciones de primera clase:

 [1, 2, 5, 10].map(function(x) { return x*x; }); 

Salida: [1, 4, 25, 100]

El método de mapa toma una función y devuelve una nueva matriz con cada elemento como resultado de la aplicación de esa función al valor en la misma posición en la matriz original.

Para hacer lo mismo es Java, con un Functor, primero debe definir una interfaz, por ejemplo:

 public interface IntMapFunction { public int f(int x); } 

Luego, si agrega una clase de colección que tenía una función de mapa, podría hacer:

 myCollection.map(new IntMapFunction() { public int f(int x) { return x * x; } }); 

Esto utiliza una subclase en línea de IntMapFunction para crear un Functor, que es el equivalente OO de la función del ejemplo anterior de JavaScript.

El uso de Functors le permite aplicar técnicas funcionales en un idioma OO. Por supuesto, algunos lenguajes OO también admiten funciones directamente, por lo que no es necesario.

Referencia: http://en.wikipedia.org/wiki/Function_object

Descripción áspera

En la progtwigción funcional, un functor es esencialmente una construcción de elevación de funciones unarias ordinarias (es decir, aquellas con un argumento) para funciones entre variables de tipos nuevos. Es mucho más fácil escribir y mantener funciones simples entre objetos planos y utilizar funtores para levantarlos, y luego escribir funciones manualmente entre objetos contenedores complicados. Otra ventaja es escribir funciones simples solo una vez y luego reutilizarlas a través de diferentes funtores.

Los ejemplos de funtores incluyen matrices, funtores “tal vez” y “cualquiera”, futuros (ver ej. https://github.com/Avaq/Fluture ), y muchos otros.

Ilustración

Considere la función de construir el nombre de la persona completa a partir del nombre y apellido. Podríamos definirlo como fullName(firstName, lastName) como función de dos argumentos, que sin embargo no sería adecuado para los funtores que solo se ocupan de las funciones de un argumento. Para remediarlo, recostackmos todos los argumentos en un solo name objeto, que ahora se convierte en el argumento único de la función:

 // In JavaScript notation fullName = name => name.firstName + ' ' + name.lastName 

Ahora que pasa si tenemos muchas personas en una matriz? En lugar de repasar manualmente la lista, simplemente podemos volver a utilizar nuestra función fullName través del método de map proporcionado para las matrices con una sola línea de código:

 fullNameList = nameList => nameList.map(fullName) 

y usarlo como

 nameList = [ {firstName: 'Steve', lastName: 'Jobs'}, {firstName: 'Bill', lastName: 'Gates'} ] fullNames = fullNameList(nameList) // => ['Steve Jobs', 'Bill Gates'] 

Eso funcionará, cada vez que cada entrada en nuestro nameList sea ​​un objeto que proporcione las firstName y lastName . Pero, ¿qué pasa si algunos objetos no lo hacen (o incluso no son objetos en absoluto)? Para evitar los errores y hacer que el código sea más seguro, podemos ajustar nuestros objetos en el tipo Maybe (por ejemplo, https://sanctuary.js.org/#maybe-type ):

 // function to test name for validity isValidName = name => (typeof name === 'object') && (typeof name.firstName === 'string') && (typeof name.lastName === 'string') // wrap into the Maybe type maybeName = name => isValidName(name) ? Just(name) : Nothing() 

donde Just(name) es un contenedor que solo contiene nombres válidos y Nothing() es el valor especial que se usa para todo lo demás. Ahora, en lugar de interrumpir (u olvidar) verificar la validez de nuestros argumentos, simplemente podemos reutilizar (levantar) nuestra función fullName original con otra línea de código, basada nuevamente en el método del map , esta vez para el tipo Maybe:

 // Maybe Object -> Maybe String maybeFullName = maybeName => maybeName.map(fullName) 

y usarlo como

 justSteve = maybeName( {firstName: 'Steve', lastName: 'Jobs'} ) // => Just({firstName: 'Steve', lastName: 'Jobs'}) notSteve = maybeName( {lastName: 'SomeJobs'} ) // => Nothing() steveFN = maybeFullName(justSteve) // => Just('Steve Jobs') notSteveFN = maybeFullName(notSteve) // => Nothing() 

Teoría de la categoría

A Functor in Category Theory es un mapa entre dos categorías que respeta la composición de sus morfismos. En un lenguaje informático , la principal categoría de interés es aquella cuyos objetos son tipos (ciertos conjuntos de valores) y cuyos morfismos son funciones f:a->b de un tipo a a otro tipo b .

Por ejemplo, tome a para ser el tipo de String , b el tipo de Número, y f es la función que asigna una cadena a su longitud:

 // f :: String -> Number f = str => str.length 

Aquí a = String representa el conjunto de todas las cadenas b = Number del conjunto de todos los números. En ese sentido, tanto a como b representan objetos en la Categoría de Conjunto (que está estrechamente relacionada con la categoría de tipos, con la diferencia de ser inesencial aquí). En la Categoría de Conjunto, los morfismos entre dos conjuntos son precisamente todas las funciones desde el primer conjunto hasta el segundo. Entonces, nuestra función de longitud f es un morfismo del conjunto de cadenas al conjunto de números.

Como solo consideramos la categoría establecida, los Funtores relevantes de ella en sí son mapas que envían objetos a objetos y morfismos a morfismos, que satisfacen ciertas leyes algebraicas.

Ejemplo: Array

Array puede significar muchas cosas, pero una sola cosa es un Functor: la construcción de tipo, mapeando un tipo a en el tipo [a] de todas las matrices de tipo a . Por ejemplo, el funcionador Array mapea el tipo String en el tipo [String] (el conjunto de todas las matrices de cadenas de longitud arbitraria), y establece el tipo Number en el tipo correspondiente [Number] (el conjunto de todas las matrices de números).

Es importante no confundir el mapa Functor

 Array :: a => [a] 

con un morfismo a -> [a] . El functor simplemente asigna (asocia) el tipo a al tipo [a] como una cosa a otra. Que cada tipo es en realidad un conjunto de elementos, no tiene relevancia aquí. Por el contrario, un morfismo es una función real entre esos conjuntos. Por ejemplo, hay un morfismo natural (función)

 pure :: a -> [a] pure = x => [x] 

que envía un valor al conjunto de 1 elemento con ese valor como entrada única. ¡Esa función no es parte del Array Functor! Desde el punto de vista de este functor, pure es solo una función como cualquier otra, nada especial.

Por otro lado, el Array Functor tiene su segunda parte: la parte de morfismo. Que asigna un morfismo f :: a -> b a un morfismo [f] :: [a] -> [b] :

 // a -> [a] Array.map(f) = arr => arr.map(f) 

Aquí arr es cualquier matriz de longitud arbitraria con valores de tipo a , y arr.map(f) es la matriz de la misma longitud con valores de tipo b , cuyas entradas son resultados de aplicar f a las entradas de arr . Para que sea un funtor, las leyes matemáticas del mapeo de la identidad con la identidad y las composiciones con las composiciones deben mantenerse, que son fáciles de verificar en este ejemplo de Array .

KISS: Un functor es un objeto que tiene un método de mapa.

Las matrices en JavaScript implementan el mapa y, por lo tanto, son funtores. Las promesas, los flujos y los árboles a menudo implementan el mapa en los lenguajes funcionales, y cuando lo hacen, se los considera funtores. El método del mapa del functor toma sus propios contenidos y transforma cada uno de ellos utilizando la callback de transformación pasada al mapa, y devuelve un nuevo funtor, que contiene la estructura como el primer funtor, pero con los valores transformados.

src: https://www.youtube.com/watch?v=DisD9ftUyCk&feature=youtu.be&t=76

En la práctica, functor significa un objeto que implementa el operador de llamada en C ++. En ocaml creo que functor se refiere a algo que toma un módulo como entrada y saca otro módulo.

En pocas palabras, un functor u objeto de función es un objeto de clase que se puede llamar como una función.

En C ++:

Así es como escribes una función

 void foo() { cout << "Hello, world! I'm a function!"; } 

Así es como escribes un functor

 class FunctorClass { public: void operator () { cout << "Hello, world! I'm a functor!"; } }; 

Ahora puedes hacer esto:

 foo(); //result: Hello, World! I'm a function! FunctorClass bar; bar(); //result: Hello, World! I'm a functor! 

Lo que los hace tan geniales es que puedes mantener el estado en la clase: imagina si quisieras preguntarle a una función cuántas veces se ha llamado. No hay forma de hacer esto de una manera ordenada y encapsulada. Con un objeto de función, es como cualquier otra clase: tendrías una variable de instancia que incrementarías en operator () y algún método para inspeccionar esa variable, y todo estaría ordenado a tu gusto.

Functor no está específicamente relacionado con la progtwigción funcional. Es solo un “puntero” a una función o algún tipo de objeto, que puede llamarse como si fuera una función.

Intereting Posts