Escovando - Currying

Em matemática e ciência da computação , currying é a técnica de converter uma função que recebe vários argumentos em uma sequência de funções, cada uma com um único argumento. Por exemplo, currying uma função que leva três argumentos cria três funções:

Ou, de forma mais abstrata, uma função que recebe dois argumentos, um de e um de , e produz resultados por currying, é traduzida em uma função que recebe um único argumento de e produz como resultados funções de para que Currying está relacionado, mas não o mesmo como, aplicação parcial .

Currying é útil tanto em ambientes práticos quanto teóricos. Em linguagens de programação funcional e em muitas outras, ele fornece uma maneira de gerenciar automaticamente como os argumentos são passados ​​para funções e exceções. Na ciência da computação teórica , ele fornece uma maneira de estudar funções com vários argumentos em modelos teóricos mais simples que fornecem apenas um argumento. O cenário mais geral para a noção estrita de currying e uncurrying está nas categorias monoidais fechadas , que sustentam uma vasta generalização da correspondência Curry-Howard de provas e programas para uma correspondência com muitas outras estruturas, incluindo mecânica quântica, cobordismos e teoria das cordas . Foi introduzido por Gottlob Frege , desenvolvido por Moses Schönfinkel e posteriormente desenvolvido por Haskell Curry .

Sem pressa é a dupla transformação para currying e pode ser vista como uma forma de desfuncionalização . Ele recebe uma função cujo valor de retorno é outra função e produz uma nova função que usa como parâmetros os argumentos para e , e retorna, como resultado, a aplicação de e subsequentemente,, a esses argumentos. O processo pode ser iterado.

Motivação

Currying fornece uma maneira de trabalhar com funções que usam vários argumentos e usá-los em estruturas em que as funções podem ter apenas um argumento. Por exemplo, algumas técnicas analíticas só podem ser aplicadas a funções com um único argumento. As funções práticas freqüentemente levam mais argumentos do que isso. Frege mostrou que era suficiente fornecer soluções para o caso de argumento único, pois era possível transformar uma função com vários argumentos em uma cadeia de funções de argumento único. Essa transformação é o processo agora conhecido como currying. Todas as funções "comuns" que podem ser tipicamente encontradas em análises matemáticas ou em programação de computador podem ser controladas. No entanto, existem categorias nas quais o currying não é possível; as categorias mais gerais que permitem currying são as categorias monoidais fechadas .

Algumas linguagens de programação quase sempre usam funções curried para obter vários argumentos; exemplos notáveis ​​são ML e Haskell , onde em ambos os casos todas as funções têm exatamente um argumento. Esta propriedade é herdada do cálculo lambda , onde funções com vários argumentos são geralmente representadas na forma curry.

Currying está relacionado, mas não é o mesmo que aplicação parcial . Na prática, a técnica de programação de closures pode ser utilizada para realizar uma aplicação parcial e uma espécie de currying, ocultando argumentos em um ambiente que viaja com a função curried.

Ilustração

Suponha que temos uma função que recebe dois argumentos de número real ( ) e produz números reais, e é definida por . Currying traduz isso em uma função que recebe um único argumento real e produz funções de para . Nos símbolos, onde denota o conjunto de todas as funções que recebem um único argumento real e produzem saídas reais. Para cada número real , defina a função por e, em seguida, defina a função por . Portanto, por exemplo, é a função que envia seu argumento real para a saída , ou . Vemos isso em geral

de modo que a função original e seu currying transmitem exatamente as mesmas informações. Nesta situação, também escrevemos

Isso também funciona para funções com mais de dois argumentos. Se fosse uma função de três argumentos , seu currying teria a propriedade

História

O nome "currying", cunhado por Christopher Strachey em 1967, é uma referência ao lógico Haskell Curry . O nome alternativo "Schönfinkelisation" foi proposto como uma referência a Moses Schönfinkel . No contexto matemático, o princípio pode ser rastreado até o trabalho em 1893 por Frege .

Definição

O currying é mais facilmente compreendido começando com uma definição informal, que pode então ser moldada para se ajustar a muitos domínios diferentes. Primeiro, há alguma notação a ser estabelecida. A notação denota todas as funções de a . Se é essa função, escrevemos . Vamos denotar os pares ordenados dos elementos de e respectivamente, isto é, o produto cartesiano de e . Aqui, e podem ser conjuntos, ou podem ser tipos, ou podem ser outros tipos de objetos, conforme explorado a seguir.

Dada uma função

,

currying constrói uma nova função

.

Ou seja, obtém um argumento de e retorna uma função que mapeia para . É definido por

para de e de . Em seguida, também escrevemos

Sem pressa é a transformação reversa, e é mais facilmente compreendida em termos de seu adjunto certo, a função

Teoria de conjuntos

Na teoria dos conjuntos , a notação é usada para denotar o conjunto de funções do conjunto para o conjunto . Currying é a bijeção natural entre o conjunto de funções de para e o conjunto de funções de para o conjunto de funções de para . Em símbolos:

Na verdade, é essa bijeção natural que justifica a notação exponencial para o conjunto de funções. Como é o caso em todas as instâncias de currying, a fórmula acima descreve um par adjunto de functores : para cada conjunto fixo , o functor é deixado adjunto ao functor .

Na categoria de conjuntos , o objeto é denominado objeto exponencial .

Espaços funcionais

Na teoria dos espaços de funções , como na análise funcional ou na teoria da homotopia , está comumente interessado em funções contínuas entre espaços topológicos . Escreve-se (o functor Hom ) para o conjunto de todas as funções de a e usa a notação para denotar o subconjunto de funções contínuas. Aqui está a bijeção

enquanto sem pressa é o mapa inverso. Se o conjunto de funções contínuas de a recebe a topologia compacta-aberta , e se o espaço é localmente compacto de Hausdorff , então

é um homeomorfismo . Este também é o caso quando , e são gerados compactamente , embora haja mais casos.

Um corolário útil é que uma função é contínua se e somente se sua forma curry for contínua. Outro resultado importante é que o mapa do aplicativo , geralmente chamado de "avaliação" neste contexto, é contínuo (observe que eval é um conceito estritamente diferente na ciência da computação). Ou seja,

é contínuo quando é compacto-aberto e localmente compacto Hausdorff. Esses dois resultados são centrais para estabelecer a continuidade da homotopia , ou seja, quando é o intervalo unitário , de modo que pode ser pensado como uma homotopia de duas funções de para , ou, equivalentemente, um único caminho (contínuo) em .

Topologia algébrica

Na topologia algébrica , currying serve como um exemplo da dualidade Eckmann-Hilton e, como tal, desempenha um papel importante em uma variedade de configurações diferentes. Por exemplo, o espaço do loop é adjacente a suspensões reduzidas ; isso é comumente escrito como

onde é o conjunto de classes de homotopia de mapas , e é a suspensão de um , e é o espaço de loop de Uma . Em essência, a suspensão pode ser vista como o produto cartesiano de com o intervalo unitário, módulo uma relação de equivalência para transformar o intervalo em um loop. A forma curry então mapeia o espaço para o espaço de funções de loops para , isto é, de para . Então é o functor adjunto que mapeia suspensões para espaços de loop, e sem pressa é o dual.

A dualidade entre o cone de mapeamento e a fibra de mapeamento ( cofibration e fibração ) pode ser entendida como uma forma de currying, que por sua vez leva à dualidade das longas sequências de Puppe exatas e coexatas .

Na álgebra homológica , a relação entre currying e uncurrying é conhecida como adjunção tensor-hom . Aqui, surge uma reviravolta interessante: o functor de Hom e o functor de produto tensorial podem não se elevar para uma sequência exata ; isso leva à definição do functor Ext e do functor Tor .

Teoria do domínio

Em teoria da ordem , isto é, a teoria das redes de conjuntos parcialmente ordenados , é uma função contínua quando a rede recebe a topologia de Scott . As funções contínuas de Scott foram investigadas pela primeira vez na tentativa de fornecer uma semântica para o cálculo lambda (já que a teoria de conjuntos comum é inadequada para fazer isso). De maneira mais geral, as funções contínuas de Scott são agora estudadas na teoria de domínio , que abrange o estudo da semântica denotacional de algoritmos de computador. Observe que a topologia Scott é bastante diferente de muitas topologias comuns que podem ser encontradas na categoria de espaços topológicos ; a topologia Scott é normalmente mais refinada e não é sóbria .

A noção de continuidade surge na teoria dos tipos de homotopia , onde, grosso modo, dois programas de computador podem ser considerados homotópicos, ou seja, computar os mesmos resultados, se puderem ser refatorados "continuamente" de um para o outro.

Lambda calculi

Na ciência da computação teórica , o currying fornece uma maneira de estudar funções com vários argumentos em modelos teóricos muito simples, como o cálculo lambda , em que as funções aceitam apenas um único argumento. Considere uma função recebendo dois argumentos e tendo o tipo , o que deve ser entendido como significando que x deve ter o tipo , y deve ter o tipo e a própria função retorna o tipo . A forma curry de f é definida como

onde está o abstrator do cálculo lambda. Uma vez que o curry tem, como entrada, funções com o tipo , conclui-se que o próprio tipo de curry é

O operador → é freqüentemente considerado associativo à direita , então o tipo de função curried é freqüentemente escrito como . Por outro lado, a aplicação da função é considerada associativa à esquerda , de modo que é equivalente a

.

Ou seja, os parênteses não são necessários para eliminar a ambiguidade da ordem da aplicação.

As funções Curried podem ser usadas em qualquer linguagem de programação que suporte encerramentos ; no entanto, funções não urgentes são geralmente preferidas por razões de eficiência, uma vez que a sobrecarga de aplicativo parcial e criação de encerramento pode então ser evitada para a maioria das chamadas de função.

Teoria de tipo

Na teoria dos tipos , a ideia geral de um sistema de tipos na ciência da computação é formalizada em uma álgebra de tipos específica. Por exemplo, ao escrever , a intenção é que e sejam tipos , enquanto a seta é um construtor de tipo , especificamente, o tipo de função ou tipo de seta. Da mesma forma, o produto cartesiano de tipos é construído pelo tipo de produto construtor .

A abordagem teórica de tipo é expressa em linguagens de programação como ML e nas linguagens derivadas e inspiradas por ela: CaML , Haskell e F # .

A abordagem teórica de tipo fornece um complemento natural para a linguagem da teoria das categorias , conforme discutido abaixo. Isso ocorre porque as categorias, e especificamente as categorias monoidais , têm uma linguagem interna , com o cálculo lambda simplesmente digitado sendo o exemplo mais proeminente de tal linguagem. É importante neste contexto, porque pode ser construído a partir de um único construtor de tipo, o tipo seta. Currying então dota a linguagem de um tipo de produto natural. A correspondência entre objetos em categorias e tipos permite então que as linguagens de programação sejam reinterpretadas como lógicas (via correspondência de Curry-Howard ) e como outros tipos de sistemas matemáticos, conforme explorado mais adiante, abaixo.

Lógica

Na correspondência de Curry-Howard , a existência de currying e uncurrying é equivalente ao teorema lógico , pois tuplas ( tipo de produto ) correspondem à conjunção na lógica, e o tipo de função corresponde à implicação.

O objeto exponencial na categoria das álgebras de Heyting é normalmente escrito como implicação material . Álgebras distributivas de Heyting são álgebras booleanas , e o objeto exponencial tem a forma explícita , deixando claro que o objeto exponencial é realmente implicação material .

Teoria da categoria

As noções acima de currying e sem pressa encontram sua declaração mais geral e abstrata na teoria das categorias . O currying é uma propriedade universal de um objeto exponencial e dá origem a uma adjunção em categorias cartesianas fechadas . Ou seja, existe um isomorfismo natural entre os morfismos de um produto binário e os morfismos para um objeto exponencial .

Isso generaliza para um resultado mais amplo em categorias monoidais fechadas : Currying é a afirmação de que o produto tensorial e o Hom interno são functores adjuntos ; ou seja, para cada objeto existe um isomorfismo natural :

Aqui, Hom denota o função Hom (externo) de todos os morfismos na categoria, enquanto denota o functor hom interno na categoria monoidal fechada. Para a categoria de conjuntos , os dois são iguais. Quando o produto é o produto cartesiano, o hom interno torna-se o objeto exponencial .

O currying pode se decompor de duas maneiras. Uma é se uma categoria não for fechada e, portanto, não tiver um functor hom interno (possivelmente porque há mais de uma escolha para tal functor). Outra maneira é se não for monoidal e, portanto, não tiver um produto (ou seja, não tiver uma maneira de escrever pares de objetos). As categorias que têm produtos e homs internos são exatamente as categorias monoidais fechadas.

O estabelecimento de categorias fechadas cartesianas é suficiente para a discussão da lógica clássica ; a configuração mais geral de categorias monoidais fechadas é adequada para computação quântica .

A diferença entre esses dois é que o produto para categorias cartesianas (como a categoria de conjuntos , pedidos parciais completos ou álgebras de Heyting ) é apenas o produto cartesiano ; é interpretado como um par ordenado de itens (ou uma lista). O cálculo lambda simplesmente digitado é a linguagem interna das categorias cartesianas fechadas; e é por esta razão que pares e listas são os tipos primários na teoria de tipo de LISP , Scheme e muitas linguagens de programação funcional .

Em contraste, o produto para categorias monoidais (como o espaço de Hilbert e os espaços vetoriais da análise funcional ) é o produto tensorial . A linguagem interna de tais categorias é a lógica linear , uma forma de lógica quântica ; o sistema de tipo correspondente é o sistema de tipo linear . Essas categorias são adequadas para descrever estados quânticos emaranhados e, de modo mais geral, permitem uma vasta generalização da correspondência de Curry-Howard para a mecânica quântica , para os cobordismos na topologia algébrica e para a teoria das cordas . O sistema de tipo linear e a lógica linear são úteis para descrever primitivas de sincronização , como bloqueios de exclusão mútua e a operação de máquinas de venda automática.

Contraste com a aplicação de função parcial

Currying e aplicação de função parcial são frequentemente confundidos. Uma das diferenças significativas entre os dois é que uma chamada para uma função parcialmente aplicada retorna o resultado imediatamente, não outra função na cadeia de currying; esta distinção pode ser ilustrada claramente para funções cuja aridade é maior que dois.

Dada uma função de tipo , o currying produz . Ou seja, enquanto uma avaliação da primeira função pode ser representada como , a avaliação da função curried seria representada como , aplicando cada argumento por vez a uma função de argumento único retornada pela chamada anterior. Observe que, após a chamada , ficamos com uma função que recebe um único argumento e retorna outra função, não uma função que recebe dois argumentos.

Em contraste, a aplicação parcial de função se refere ao processo de fixar um número de argumentos a uma função, produzindo outra função de menor aridade. Dada a definição acima, podemos corrigir (ou 'vincular') o primeiro argumento, produzindo uma função do tipo . A avaliação desta função pode ser representada como . Observe que o resultado da aplicação parcial da função, neste caso, é uma função que recebe dois argumentos.

Intuitivamente, o aplicativo de função parcial diz "se você corrigir o primeiro argumento da função, obterá uma função dos argumentos restantes". Por exemplo, se a função div representa a operação de divisão x / y , então div com o parâmetro x fixado em 1 (ou seja, div 1) é outra função: o mesmo que a função inv que retorna o inverso multiplicativo de seu argumento, definido por inv ( y ) = 1 / y .

A motivação prática para a aplicação parcial é que muitas vezes as funções obtidas fornecendo alguns, mas não todos os argumentos para uma função, são úteis; por exemplo, muitos idiomas têm uma função ou operador semelhante a plus_one. A aplicação parcial facilita a definição dessas funções, por exemplo, criando uma função que representa o operador de adição com 1 limite como seu primeiro argumento.

A aplicação parcial pode ser vista como a avaliação de uma função curried em um ponto fixo, por exemplo, dado e então ou simplesmente onde o primeiro parâmetro de curries f.

Assim, a aplicação parcial é reduzida a uma função curry em um ponto fixo. Além disso, uma função curried em um ponto fixo é (trivialmente) uma aplicação parcial. Para obter mais evidências, observe que, dada qualquer função , uma função pode ser definida de modo que . Assim, qualquer aplicação parcial pode ser reduzida a uma única operação de curry. Como tal, curry é mais adequadamente definido como uma operação que, em muitos casos teóricos, é frequentemente aplicada recursivamente, mas que é teoricamente indistinguível (quando considerada como uma operação) de uma aplicação parcial.

Assim, uma aplicação parcial pode ser definida como o resultado objetivo de uma única aplicação do operador curry em alguma ordenação das entradas de alguma função.

Veja também

Notas

Referências

links externos