Función de orden superior

AjustarCompartirImprimirCitar
Función que toma una o más funciones como entrada o que produce una función

En matemáticas e informática, una función de orden superior (HOF) es una función que hace al menos una de las siguientes cosas:

  • toma una o más funciones como argumentos (es decir, un parámetro de procedimiento, que es un parámetro de un procedimiento que es en sí mismo un procedimiento),
  • devuelve una función como resultado.

Todas las demás funciones son funciones de primer orden. En matemáticas, las funciones de orden superior también se denominan operadores o funcionales. El operador diferencial en cálculo es un ejemplo común, ya que asigna una función a su derivada, también una función. Las funciones de orden superior no deben confundirse con otros usos de la palabra "funtor" a lo largo de las matemáticas, consulte Funtor (desambiguación).

En el cálculo de lambda no tipo, todas las funciones son de mayor orden; en un cálculo de lambda tipo, del cual se derivan la mayoría de los lenguajes de programación funcionales, funciones de mayor orden que toman una función como argumento son valores con tipos de la forma ()τ τ 1→ → τ τ 2)→ → τ τ 3{displaystyle (tau _{1}to tau _{2})to tau _{3}}.

Ejemplos generales

  • map función, encontrada en muchos lenguajes de programación funcionales, es un ejemplo de una función de orden superior. Toma como argumentos una función f y una colección de elementos, y como resultado, devuelve una nueva colección con f aplicado a cada elemento de la colección.
  • Funciones de clasificación, que tienen una función de comparación como parámetro, permitiendo al programador separar el algoritmo de clasificación de las comparaciones de los elementos que se clasifican. Función estándar C qsort es un ejemplo de esto.
  • filtro
  • plegable
  • aplicación
  • Composición de funciones
  • Integración
  • Callback
  • Traversal de árboles
  • Gramática Montague, teoría semántica del lenguaje natural, utiliza funciones de orden superior

Soporte en lenguajes de programación

Soporte directo

Los ejemplos no pretenden comparar y contrastar lenguajes de programación, sino servir como ejemplos de sintaxis de funciones de orden superior

En los siguientes ejemplos, la función de orden superior dos veces toma una función y aplica la función a algún valor dos veces. Si dos veces tiene que aplicarse varias veces para el mismo f preferiblemente debería devolver una función en lugar de un valor. Esto está en línea con el "no te repitas" principio.

APL

 Dos veces.{}⍺⍺ ⍺⍺ } más tres{}+3} g{}más tres Dos veces. }  g 713

O de manera tácita:

 Dos veces.2 más tres+3 gmás tres Dos veces.  g 713

C++

Usando std::function en C+ +11:

#include ■iostream#include Identificadoauto Dos veces. = [](const std::función.int()int) f){} retorno [f]int x) {} retorno f()f()x)); };};auto plus_tres = [](int i){} retorno i + 3;};int principal(){} auto g = Dos veces.()plus_tres); std::Cout .. g()7) .. 'n '; // 13}

O, con lambdas genéricas proporcionadas por C++14:

#include ■iostreamauto Dos veces. = [](const auto" f){} retorno [f]int x) {} retorno f()f()x)); };};auto plus_tres = [](int i){} retorno i + 3;};int principal(){} auto g = Dos veces.()plus_tres); std::Cout .. g()7) .. 'n '; // 13}

C#

Usando solo delegados:

utilizando Sistema;público clase Programa{} público estática vacío Main()cuerda[] args) {} Func.Func.int, int, Func.int, int> Dos veces. = f = x = f()f()x)); Func.int, int más = i = i + 3; Var g = Dos veces.()más); Consola.WriteLine()g()7)); // 13 }}

O de manera equivalente, con métodos estáticos:

utilizando Sistema;público clase Programa{} privado estática Func.int, int Dos veces.()Func.int, int f) {} retorno x = f()f()x)); } privado estática int PlusThree()int i) = i + 3; público estática vacío Main()cuerda[] args) {} Var g = Dos veces.()PlusThree); Consola.WriteLine()g()7)); // 13 }}

Cierre

()defn Dos veces. [f] ()f [x] ()f ()f x)))()defn más tres [i] ()+ i 3)()def g ()Dos veces. más tres)()println ()g 7) ; 13

Lenguaje de marcado ColdFusion (CFML)

Dos veces. = función()f) {} retorno función()x) {} retorno f()f()x)); };};más = función()i) {} retorno i + 3;};g = Dos veces.()más);scriptOutput()g()7)); // 13

Ceceo común

()defun Dos veces. ()f)  ()lambda ()x) ()funcall f ()funcall f x)))  ()defun más tres ()i)  ()+ i 3)  ()defvar g ()Dos veces. # 'más tres)  ()impresión ()funcall g 7)

D

importación std.Idiota. : Writeln;alias Dos veces. = ()f) = ()int x) = f()f()x));alias más = ()int i) = i + 3;vacío principal(){} auto g = Dos veces.()más); Writeln()g()7)); // 13}

Dardo

int Función()int) Dos veces.()int Función()int) f) {} retorno ()x) {} retorno f()f()x)); };}int más()int i) {} retorno i + 3;}vacío principal() {} final g = Dos veces.()más);  impresión()g()7)); // 13}

Elixir

En Elixir, puede mezclar definiciones de módulos y funciones anónimas

defmodule Hof do def Dos veces.()f) do f()x) - f.()f.()x) final finalfinalplus_tres = f()i) - i + 3 finalg = Hof.Dos veces.()plus_tres)IO.puts g.()7) # 13

Alternativamente, también podemos componer usando funciones anónimas puras.

Dos veces. = f()f) - f()x) - f.()f.()x) finalfinalplus_tres = f()i) - i + 3 finalg = Dos veces..()plus_tres)IO.puts g.()7) # 13

Erlang

or_else([], _) - falso;or_else[F Silencio Fs] X) - or_else()Fs, X, F()X)).or_else()Fs, X, falso) - or_else()Fs, X);or_else()Fs, _ {}falso, Y}) - or_else()Fs, Y);or_else(_ _ R) - R.or_else[diversión erlang:is_integer/1, diversión erlang:is_atom/1, diversión erlang:is_list/1] 3.23).

En este ejemplo de Erlang, la función de orden superior or_else/ 2 toma una lista de funciones (Fs) y argumento (X). Evalúa la función F con el argumento X como argumento. Si la función F devuelve falso, entonces la siguiente función en Se evaluará Fs. Si la función F devuelve {false, Y} luego la siguiente función en Fs con el argumento Y. Si la función F devuelve R la función de orden superior or_else/2 devolverá R. Tenga en cuenta que X, Y, y R pueden ser funciones. El ejemplo devuelve false.

F#

Deja Dos veces. f = f > fDeja plus_tres = (+) 3Deja g = Dos veces. plus_tresg 7  printf "%A" // 13

Ir

paquete principalimportación "Fmt"func Dos veces.()f func()int) int) func()int) int {}retorno func()x int) int {}retorno f()f()x)}}func principal() {}más := func()i int) int {}retorno i + 3}g := Dos veces.()más)Fmt.Println()g()7) // 13}

Observe que un literal de función se puede definir con un identificador ( dos veces) o de forma anónima (asignado a la variable plusThree).

Haskell

Dos veces. :: ()Int - Int) - ()Int - Int)Dos veces. f = f . fmás :: Int - Intmás = ()+3)principal :: IO ()principal = impresión ()g 7) - 13 Donde g = Dos veces. más

J

Explícitamente,

 Dos veces.=. adverb : 'uuu ' más tres=. verbo : 'y + 3 '  g=. más tres Dos veces.  g 713

o tácitamente,

 Dos veces.=. ^:2 más tres=. +3  g=. más tres Dos veces.  g 713

Java (1.8+)

Usando solo interfaces funcionales:

importación Java.util. *;clase Main {} público estática vacío principal()String[] args) {} Función.IntUnaryOperator, IntUnaryOperator Dos veces. = f - f.y Entonces...()f); IntUnaryOperator más = i - i + 3; Var g = Dos veces..aplicación()más); Sistema.Fuera..println()g.aplicaAsInt()7)); // 13 }}

O de manera equivalente, con métodos estáticos:

importación Java.util. *;clase Main {} privado estática IntUnaryOperator Dos veces.()IntUnaryOperator f) {} retorno f.y Entonces...()f); } privado estática int más()int i) {} retorno i + 3; } público estática vacío principal()String[] args) {} Var g = Dos veces.()Main::más); Sistema.Fuera..println()g.aplicaAsInt()7)); // 13 }}

JavaScript

Con funciones de flecha:

"uso estricto";const Dos veces. = f = x = f()f()x));const más = i = i + 3;const g = Dos veces.()más);consola.log()g()7)); // 13

O con sintaxis clásica:

"uso estricto";función Dos veces.()f) {} retorno función ()x) {} retorno f()f()x)); };}función más()i) {} retorno i + 3;}const g = Dos veces.()más);consola.log()g()7)); // 13

Julia

julia función Dos veces.()f) función resultado()x) retorno f()f()x) final retorno resultado finaldos veces (función genética con 1 método)julia más tres()i) = i + 3más tres (función genética con 1 método)julia g = Dos veces.()más tres)(:var"#result#3"{typeof(plusthree)}) (función genética con 1 método)julia g()7)13

Kotlin

diversión Dos veces.()f: ()Int) - Int): ()Int) - Int {} retorno {} f()f()es) }}diversión más()i: Int) = i + 3diversión principal() {} val g = Dos veces.()::más) println()g()7) // 13}

Lúa

función Dos veces.()f) retorno función ()x) retorno f()f()x) finalfinalfunción más()i) retorno i + 3finallocal g = Dos veces.()más)impresión()g()7) - 13

MATLAB

función resultado = Dos veces.()f)resultado = @(x) f()f()x));finalmás tres = @(i) i + 3;g = Dos veces.()más tres)disp()g()7)); % 13

OCaml

Deja Dos veces. f x = f ()f x)Deja plus_tres = (+) 3Deja () = Deja g = Dos veces. plus_tres dentro print_int ()g 7); (* 13 *) print_newline ()

PHP

Identificado?phpDeclara()strict_types=1);función Dos veces.()callable $f): Clausura {} retorno función ()int $x) uso ()$f): int {} retorno $f()$f()$x)); };}función más()int $i): int {} retorno $i + 3;}$g = Dos veces.()'plus Tres. ');eco $g()7), "n"; // 13

o con todas las funciones en variables:

Identificado?phpDeclara()strict_types=1);Dos veces. = f()callable $f): Clausura = f()int $x): int = $f()$f()$x));$plusThree = f()int $i): int = $i + 3;$g = Dos veces.()$plusThree);eco $g()7), "n"; // 13

Tenga en cuenta que las funciones de flecha capturan implícitamente cualquier variable que provenga del ámbito principal, mientras que las funciones anónimas requieren el use palabra clave para hacer lo mismo.

Perl

uso estricto;uso advertencias;sub Dos veces. {} # ()$f) = @_; sub {} $f-()$f-()@_)); };}sub más {} # ()$i) = @_; $i + 3;}# $g = Dos veces.()más);impresión $g-()7), "n"; # 13

o con todas las funciones en variables:

uso estricto;uso advertencias;# Dos veces. = sub {} # ()$f) = @_; sub {} $f-()$f-()@_)); };};# $plusThree = sub {} # ()$i) = @_; $i + 3;};# $g = Dos veces.-()$plusThree);impresión $g-()7), "n"; # 13

Pitón

, titulado def Dos veces.()f):...  def resultado()x):...  retorno f()f()x)...  retorno resultado, titulado plus_tres = lambda i: i + 3, titulado g = Dos veces.()plus_tres) , titulado g()7)13

La sintaxis del decorador de Python se usa a menudo para reemplazar una función con el resultado de pasar esa función a través de una función de orden superior. Por ejemplo, la función g podría implementarse de manera equivalente:

, titulado @twice... def g()i):...  retorno i + 3, titulado g()7)13

R

Dos veces. . función()f) {} retorno()función()x) {} f()f()x) })}más . función()i) {} retorno()i + 3)}g . Dos veces.()más) impresión()g()7)[1] 13

Raku

sub Dos veces.()Callable:D $fretorno sub {} $f()$f()$^x) };
}

sub más()Int:D $iretorno $i + 3;
}

# $g = Dos veces.()" + tres ");

Di: $g()7); # 13

En Raku, todos los objetos de código son cierres y, por lo tanto, pueden hacer referencia a "lexical" variables de un ámbito externo porque la variable léxica está "cerrada" dentro de la función. Raku también es compatible con "bloque puntiagudo" sintaxis para expresiones lambda que se pueden asignar a una variable o invocar de forma anónima.

Rubí

def Dos veces.()f) -()x) {} f.llamada()f.llamada()x) }finalplus_tres = -()i) {} i + 3 }g = Dos veces.()plus_tres)puts g.llamada()7) # 13

Óxido

f Dos veces.()f: impl Fn()i32) - i32) - impl Fn()i32) - i32 {} Muévanse. SilencioxSilencio f()f()x)}f plus_tres()i: i32) - i32 {} i + 3}f principal() {} Deja g = Dos veces.()plus_tres); ¡Imprimir!()"{}", g()7) // 13}

Escala

objeto Main {} def Dos veces.()f: Int = Int): Int = Int = f compose f def más()i: Int): Int = i + 3 def principal()args: Array[String] Dependencia = {} val g = Dos veces.()más) impresión()g()7) // 13 }}

Esquema

()definir ()Dos veces. f)  ()lambda ()x) ()f ()f x)))()definir ()más tres i) ()+ i 3)()definir g ()Dos veces. más tres)()pantalla ()g 7) ; 13()pantalla "n")

Rápido

func Dos veces.()¿Qué? f: @escapar ()Int) - Int) - ()Int) - Int {} retorno {} f()f()$0) }}Deja más = {} $0 + 3 }Deja g = Dos veces.()más)impresión()g()7) // 13

Tcl

set Dos veces. {} {}f x} {apply} $f [apply] $f $x]set más {} {}i} Retorno [exprador] $i + 3]# result: 13puts [apply] Dos veces. $plusThree 7]

Tcl usa el comando apply para aplicar una función anónima (desde 8.6).

XACML

El estándar XACML define funciones de orden superior en el estándar para aplicar una función a múltiples valores de paquetes de atributos.

Regla permitir Entrada{} permiso condición cualquier(función)[stringEqual] ciudadanías, permitidoCitizenships)}

La lista de funciones de orden superior en XACML se puede encontrar aquí.

XQuery

Declara función local: dos veces()$f, $x) {} $f()$f()$x)};Declara función local: más de tres()$i) {} $i + 3};local: dos veces()local: más de tres#1, 7) (: 13:)

Alternativas

Puntero de función

Los punteros de función en lenguajes como C, C++ y Pascal permiten a los programadores pasar referencias a funciones. El siguiente código C calcula una aproximación de la integral de una función arbitraria:

#include Identificado.hdoble cuadrado()doble x){} retorno x * x;}doble cube()doble x){} retorno x * x * x;}/* Computar la integral de f() dentro del intervalo [a,b] */doble integral()doble f()doble x), doble a, doble b, int n){} int i; doble suma = 0; doble  = ()b - a) / n; para ()i = 0; i . n; ++i) {} suma += f()a + ()i + 0.5) * ); } retorno suma * ;}int principal(){} printf()#n", integral()cuadrado, 0, 1, 100)); printf()#n", integral()cube, 0, 1, 100)); retorno 0;}

La función qsort de la biblioteca estándar de C utiliza un puntero de función para emular el comportamiento de una función de orden superior.

Macros

Las macros también se pueden usar para lograr algunos de los efectos de las funciones de orden superior. Sin embargo, las macros no pueden evitar fácilmente el problema de la captura de variables; también pueden generar grandes cantidades de código duplicado, lo que puede ser más difícil de optimizar para un compilador. Las macros generalmente no están fuertemente tipadas, aunque pueden producir código fuertemente tipado.

Evaluación de código dinámico

En otros lenguajes de programación imperativos, es posible lograr algunos de los mismos resultados algorítmicos que se obtienen a través de funciones de orden superior mediante la ejecución dinámica de código (a veces llamado Eval o Execute operaciones) en el ámbito de evaluación. Puede haber inconvenientes significativos en este enfoque:

  • El código argumental a ejecutar normalmente no es de tipo estatico; estos idiomas generalmente dependen de la escritura dinámica para determinar la forma y seguridad del código a ejecutar.
  • El argumento generalmente se proporciona como una cadena, cuyo valor puede no ser conocido hasta el tiempo de ejecución. Esta cadena debe ser compilada durante la ejecución del programa (utilizando la compilación justo a tiempo) o evaluada por interpretación, causando algunos gastos generales adicionales en tiempo de ejecución, y generalmente generando código menos eficiente.

Objetos

En los lenguajes de programación orientados a objetos que no admiten funciones de orden superior, los objetos pueden ser un sustituto eficaz. Los métodos de un objeto actúan en esencia como funciones, y un método puede aceptar objetos como parámetros y producir objetos como valores devueltos. Sin embargo, los objetos a menudo conllevan una sobrecarga de tiempo de ejecución adicional en comparación con las funciones puras y un código repetitivo agregado para definir e instanciar un objeto y sus métodos. Los lenguajes que permiten estructuras o objetos basados en pila (en lugar de en montón) pueden proporcionar más flexibilidad con este método.

Un ejemplo del uso de un registro basado en una pila simple en Free Pascal con una función que devuelve una función:

programa ejemplo;Tipo  int = entero; Txy = récord x, Sí.: int; final; Tf = función ()xy: Txy): int; función f()xy: Txy): int; comenzar  Resultado := xy.Sí. + xy.x; final;función g()func: Tf): Tf; comenzar  resultado := func; final;Var  a: Tf; xy: Txy = ()x: 3; Sí.: 7);comenzar  a := g()@f); // devolver una función a "a" Writeln()a()xy); //impresión 10final.

La función a() toma un registro Txy como entrada y devuelve el valor entero de la suma de las x del registro > y y campos (3 + 7).

Desfuncionalización

La desfuncionalización se puede utilizar para implementar funciones de orden superior en lenguajes que carecen de funciones de primera clase:

// Estructuras de datos de función desfuncionalizadaplantilla.nombre T struct Añadir {} T valor; };plantilla.nombre T struct DivBy {} T valor; };plantilla.nombre F, nombre G struct Composition {} F f; G g; };// Implementaciones de aplicaciones de función desfuncionalizadaplantilla.nombre F, nombre G, nombre Xauto aplicación()Composition.F, G f, X arg) {} retorno aplicación()f.f, aplicación()f.g, arg));}plantilla.nombre T, nombre Xauto aplicación()Añadir.T f, X arg) {} retorno arg + f.valor;}plantilla.nombre T, nombre Xauto aplicación()DivBy.T f, X arg) {} retorno arg / f.valor;}// Función de composición de orden superiorplantilla.nombre F, nombre GComposition.F, G compose()F f, G g) {} retorno Composition.F, G {}f, g};}int principal()int argc, const char* argv[]) {} auto f = compose()DivBy.flotador{} 2.0f } Añadir.int{} 5 }); aplicación()f, 3); // 4.0f aplicación()f, 9); // 7.0f retorno 0;}

En este caso, se utilizan diferentes tipos para activar diferentes funciones a través de la sobrecarga de funciones. La función sobrecargada en este ejemplo tiene la firma auto apply.

Contenido relacionado

Lógica resistencia-transistor

Lógica resistencia-transistor a veces también conocida como lógica transistor-resistencia es una clase de circuitos digitales construidos utilizando...

Programación entera

Un problema de programación entera es un programa de optimización o viabilidad matemática en el que algunas o todas las variables están restringidas a ser...

Singleton (matemáticas)

En matemáticas, a singleton, también conocido como conjunto o un punto, es un conjunto con exactamente un elemento. Por ejemplo, el conjunto...
Más resultados...
Tamaño del texto: