Tango-br
  • Introduction
  • Começando
    • Índice
    • Recado do desenvolvedor
    • O que é a Tango?
    • Por onde começar?
  • Instalação
    • Instalação via NuGet
    • Instalação manual
  • Conceitos
    • Introdução
    • Utilizando comparação de padrões (Pattern Matching)
    • Valores Opcionais
    • Valores "Ou um ou outro" (Either)
    • Saindo do void para o Unit
    • Delegates Func e Action
    • Utilizando operações encadeadas com processos contínuos
    • Currying e Aplicação Parcial
  • Funcional
    • Introdução
    • Currying
    • Aplicação Parcial
    • Extensões
    • Cast Rápido para Delegates
  • Operações
    • Introdução
    • Operações com Booleans
    • Operações com Inteiros
    • Operações com Decimais
    • Operações com Doubles
    • Operações com Strings
  • Tipos
    • Introdução
    • Unit
    • Option<T>
    • Either<TLeft, TRight>
    • Continuation<TFail, TSuccess>
  • Módulos
    • Introdução
    • Option
      • Apply
      • AsEnumerable
      • Bind
      • Count
      • Exists
      • Filter
      • Fold
      • FoldBack
      • Iterate
      • Map
      • OfNullable
      • ToArray
      • ToList
      • ToNullable
    • Either
      • Exists
      • Iterate
      • Fold
      • FoldBack
      • Map
      • Swap
      • ToTuple
    • Continuation
      • AsContinuation
      • Resolve
      • Reject
      • All
    • Collection
      • Append
      • Choose
      • ChunkBySize
      • Collect
      • CompareWith
      • CountBy
      • Concat
      • Distinct
      • Empty
      • Exists
      • Exists2
      • Filter
      • FindIndex
      • Fold
      • Fold2
      • FoldBack
      • FoldBack2
      • ForAll
      • ForAll2
      • ForAll3
      • Head
      • HeadAndTailEnd
      • Range
      • Generate
      • Initialize
      • Iterate
      • Iterate2
      • IterateIndexed
      • IterateIndexed2
      • Map
      • Map2
      • Map3
      • MapIndexed
      • MapIndexed2
      • MapIndexed3
      • Partition
      • Permute
      • Pick
      • Reduce
      • ReduceBack
      • Replicate
      • Scan
      • Scan2
      • ScanBack
      • ScanBack2
      • Tail
      • TryFind
      • TryPick
      • Unzip
      • Unzip3
      • Zip
      • Zip3
  • Extensões
    • Introdução
    • Extensões para Enum
    • Construtor de EqualityComparer
    • Módulos como extensão
Powered by GitBook
On this page
  • Entendendo Currying
  • Entendendo a Aplicação Parcial

Was this helpful?

  1. Conceitos

Currying e Aplicação Parcial

Currying e aplicação parcial são dois conceitos bastante presentes na programação funcional. Os dois conceitos operam diretamente em funções com o objetivo de alterar seu tipo.

Primeiro vamos entender como exemplificar o tipo de uma função, para isso, vamos utilizar uma sintaxe parecida com a sintaxe utilizada na linguagem F#, também da plataforma .NET.

Em F# o tipo da função é definido por: parâmetro -> retorno

Logo, uma função com um parâmetro do tipo int e um retorno do tipo bool pode ser descrita como: int -> bool

Quando houverem múltiplos parâmetros iremos representar aqui (diferente do F#) como: int, int, int -> bool

Com isso, estabelecemos uma sintaxe para definir o tipo de uma função.

Agora vamos entender o problema que estas duas técnicas auxiliam na resolução.

A programação funcional é baseada principalmente no conceito de funções. Por definição, uma função matemática deve possuir apenas um parâmetro (domínio) e um retorno (alcance).

Logo, isso implicaria que, todas as funções escritas em um código funcional devem conter apenas um parâmetro, como fazer isso? - Currying

Entendendo Currying

O processo de currying consiste em quebrar funções de N parâmetros em N funções, onde cada função irá receber apenas um parâmetro e retornar uma nova função que espera os parâmetros restantes.

Logo, uma função de soma, que seria representada por: int, int -> int

Ao passar pelo processo de currying pode ser representada por: int -> int -> int

Vamos realizar um passo-a-passo do processo de currying em uma função simples, que realiza a soma de 2 valores.

Primeiro vamos definir a função como:

Func<int, int, int> add = 
    (value, value2) => value + value2;

Podemos utilizar esta função normalmente, conforme código:

int result
Func<int, int, int> add = (value, value2) => value + value2;
result = add(2, 3);
//result = 5

Ao realizar o processo de currying na função add o retorno será uma função do tipo Func<int, Func<int,int>>, ou seja, será uma função que receberá um valor inteiro e retornará um nova função esperando o segundo valor inteiro.

Quando esta segunda função receber o último parâmetro ela irá realizar o processamento proposto por add.

Veja como podemos realizar o currying com a Tango.

Func<int, int, int> add = 
    (value, value2) => value + value2;

Func<int, Func<int, int>> addCurried = Currying.Curry(add);
curriedResult = addCurried(2)(3);
//curriedResult = 5

Veja que a forma de informar os parâmetros na função addCurried é um pouco diferente, isso porque ele gera uma série de funções, onde cada uma espera apenas um parâmetro.

A Tango também fornece o Curry através de métodos de extensão para os delegates Func, portanto ao você também poderá realizar a operação descrita anteriormente da seguinte forma:

Func<int, int, int> add =
(value, value2) => value + value2;

//Func<int, Func<int, int>> addCurried = Currying.Curry(add);
Func<int, Func<int, int>> addCurried = add.Curry();
curriedResult = addCurried(2)(3);
//curriedResult = 5

Entendendo a Aplicação Parcial

A aplicação parcial é um pouco diferente do processo de Currying, mas também envolve a questão dos tipos de uma função.

Através da aplicação parcial é possível realizar a chamada de um método sem informarmos todos os parâmetros. Como resultado desta operação, será retornada uma nova função que espera todos os parâmetros restantes.

Veja as diferenças entre Currying e aplicação parcial em uma função que soma três números inteiros.

Esta seria o tipo da função de soma: int, int, int -> int

Ao realizar o Currying nesta função o resultado obtido seria: int -> int -> int -> int

Neste ponto a aplicação parcial funciona completamente diferente do processo de Currying, poderíamos inclusive, realizar diferentes aplicações parciais nesta função.

Ao informar apenas um parâmetro o resultado obtido seria: int, int -> int

Informando dois parâmetros o resultado obtido seria: int -> int

Similar ao processo de Currying, a operação fundamental descrita pela função só é executada quando todos os parâmetros forem informados, independente da quantidade de funções intermediárias geradas.

Veja a implementação descrita, primeiro através de currying:

Func<int, int, int, int> add = 
    (value, value2) => value + value2;

Func<int, Func<int, Func<int, int>>> addCurried = add.Curry();
curriedResult = addCurried(2)(3)(5);
//curriedResult = 10

Utilizando aplicação parcial com apenas um parâmetro:

Func<int, int, int, int> add = 
    (value, value2) => value + value2;

Func<int, int, int> addPartialApplied = add.PartialApply(2);
partialAppliedResult = addPartialApplied (3,5);
//partialAppliedResult = 10

Utilizando aplicação parcial com dois parâmetros:

Func<int, int, int, int> add = 
    (value, value2) => value + value2;

Func<int, int> addPartialApplied = add.PartialApply(2,3);
partialAppliedResult = addPartialApplied(5);
//partialAppliedResult = 10

Todos os métodos disponíveis para aplicação parcial e Currying operam em métodos de até 4 parâmetros, podendo retornar qualquer tipo, inclusive void.

Além disso, eles podem ser utilizados como métodos estáticos das classes Currying e PartialApplication ou como extensões para Func e Action.

PreviousUtilizando operações encadeadas com processos contínuosNextIntrodução

Last updated 5 years ago

Was this helpful?