# Continuation\<TFail, TSuccess>

> [`Tango.Types.Continuation<TFail, TSuccess>`](https://github.com/gabrielschade/Tango/blob/master/Tango/Tango/Types/Continuation.cs)

Esta classe representa valores que permitem encadeamento através de pipeline.

Instâncias de `Continuation<TFail, TSuccess>` encapsulam um valor que pode pertencer a um dos dois possíveis tipos: `TFail` ou `TSuccess`.

Neste ponto o tipo `Continuation` é muito semelhante ao tipo `Either`, mas as semelhanças acabam por aí. O propósito dos dois tipos é bastante distinto.

Enquanto o tipo `Either` encarrega-se de armazenar um dos dois valores possíveis, o tipo `Continuation`, além de também fazer isso, expõe uma série de métodos e operadores para criar um fluxo idiomático, sofisticado e poderoso para composição de seus métodos.

Devido à natureza deste tipo, não há uma demanda para compará-lo em conjunto com outro `Continuation`, por conta disso, este tipo não possui nenhuma implementação para o método `Match2`.

Ao invés disso, existem os métodos `Then` e `Catch`, que devem ser utilizados respectivamente para dar continuídade à composição quando a operação anterior foi bem sucedida e mal sucedida.

Através destes dois métodos a estrutura `Continuation` gera um pipeline entre duas ou mais funções, conectando sempre a saída de uma função como parâmetro da função seguinte.

Caso você tenha uma função f definida por `A -> B` e uma função g definida por `B -> C`, será possível criar uma nova função fg `A -> C` conectando o retorno de f como parâmetro de entrada para a função g.

Os valores `Continuation` possuem dois estados:

* Sucesso - Quando contém um valor do tipo `TSuccess`;
* Falha - Quando contém um valor do tipo `TFail`.

## Propriedades

| Nome      | Tipo | Descrição                                                                                                                |
| --------- | ---- | ------------------------------------------------------------------------------------------------------------------------ |
| IsSuccess | bool | Retorna true quando o valor contido no tipo Continuation é do tipo definido por TSuccess. Representa o estado "Sucesso". |
| IsFail    | bool | Retorna true quando o valor contido no tipo Continuation é do tipo definido por TFail. Representa o estado "Falha".      |

## Construtores

| Parâmetros       | Retorno                        | Descrição                                                                                                                  |
| ---------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
| TSuccess success | Continuation\<TFail, TSuccess> | Inicializa uma nova instância de um valor Continuation com o estado IsSuccess encapsulando o valor informado no parâmetro. |
| TFail fail       | Continuation\<TFail, TSuccess> | Inicializa uma nova instância de um valor Continuation com o estado IsFail encapsulando o valor informado no parâmetro.    |

## Métodos

| Nome    | Parâmetros                                                                                                          | Retorno                                                                     | Descrição                                                                                                                                                                                                                                                                                                                                                                                                      |
| ------- | ------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Return  | TSuccess success                                                                                                    | Continuation\<TFail, TSuccess>                                              | Inicializa uma nova instância de um valor Continuation com o estado IsSuccess encapsulando o valor informado no parâmetro.                                                                                                                                                                                                                                                                                     |
| Return  | TFail fail                                                                                                          | Continuation\<TFail, TSuccess>                                              | Inicializa uma nova instância de um valor Continuation com o estado IsFail encapsulando o valor informado no parâmetro.                                                                                                                                                                                                                                                                                        |
| Match   | <p>Func&#x3C;TSuccess,TResult> methodWhenSuccess</p><p>Func&#x3C;TFail, TResult> methodWhenFail</p>                 | TSuccess                                                                    | <p>Permite uma maneira de aplicar um método à um valor Continuation sem necessidade de checar o estado do valor.</p><p>Para isso são passados dois métodos por parâmetro. Estes métodos precisam retornar o mesmo tipo e cada um deles deve esperar um parâmetro diferente, dos tipos TFail e TSuccess. Eles serão chamados de acordo com o estado do valor Continuation (IsFail ou IsSuccess).</p>            |
| Match   | <p>Action&#x3C;TSuccess> methodWhenSuccess</p><p>Action&#x3C;TFail> methodWhenFail</p>                              | Unit                                                                        | <p>Permite uma maneira de aplicar um método à um valor Continuation sem necessidade de checar o estado do valor.</p><p>Para isso são passados dois métodos por parâmetro. Estes métodos precisam não conter retorno (void) e cada um deles deve esperar um parâmetro diferente, dos tipos TFail e TSuccess. Eles serão chamados de acordo com o estado do valor Either (IsFail ou IsSuccess).</p>              |
| Then    | Func\<TSuccess, Continuation\<TFail, TSuccess>> thenMethod                                                          | Continuation\<TFail, TSuccess>                                              | Permite uma maneira sofisticada e poderosa de compor um método através de diferentes funções. Quando o valor armazenado em Continuation estiver no estado IsSuccess o método informado no parâmetro é executado utilizando o valor armazenado no Continuation como parâmetro, caso contrário ocorre apenas um bypass até um método Catch ser encontrado.                                                       |
| Then    | Func\<TSuccess, Continuation\<TFail, TNewSuccess>> thenMethod                                                       | Continuation\<TFail, TNewSuccess>                                           | Permite uma maneira sofisticada e poderosa de compor um método através de diferentes funções. Quando o valor armazenado em Continuation estiver no estado IsSuccess o método informado no parâmetro é executado utilizando o valor armazenado no Continuation como parâmetro, caso contrário ocorre apenas um bypass até um método Catch ser encontrado.                                                       |
| Then    | <p>Func&#x3C;TParameter, TSuccess, Continuation&#x3C;TFail, TNewSuccess>> thenMethod</p><p>TParameter parameter</p> | Continuation\<TFail, TNewSuccess>                                           | Permite uma maneira sofisticada e poderosa de compor um método que contém através de diferentes funções. Quando o valor armazenado em Continuation estiver no estado IsSuccess o método informado no parâmetro é executado utilizando o valor armazenado no Continuation e o valor informado em parameter, como os dois parâmetros. Caso contrário ocorre apenas um bypass até um método Catch ser encontrado. |
| Catch   | Func\<TFail, Continuation\<TFail, TSuccess>> catchMethod                                                            | Continuation\<TFail, TSuccess>                                              | Permite uma maneira sofisticada e poderosa de compor um método que contém através de diferentes funções. Quando o valor armazenado em Continuation estiver no estado IsFail o método informado no parâmetro é executado utilizando o valor armazenado no Continuation. Caso contrário ocorre apenas um bypass até um método Then ser encontrado.                                                               |
| Catch   | Func\<TFail, Continuation\<TNewFail, TSuccess>> catchMethod                                                         | Continuation\<TNewFail, TSuccess>                                           | Permite uma maneira sofisticada e poderosa de compor um método que contém através de diferentes funções. Quando o valor armazenado em Continuation estiver no estado IsFail o método informado no parâmetro é executado utilizando o valor armazenado no Continuation. Caso contrário ocorre apenas um bypass até um método Then ser encontrado.                                                               |
| Finally | Action finallyMethod                                                                                                | Continuation\<TFail, TSuccess>                                              | Permite uma maneira de criar um código que deve ser executado no Continuation\<TFail, TSuccess> independente de seu estado, com isso, evitando duplicar código nos métodos Then e Catch.                                                                                                                                                                                                                       |
| Finally | Action< Either\<TFail,TSuccess> > finallyMethod                                                                     | Continuation\<TFail, TSuccess>                                              | Permite uma maneira de criar um código que deve ser executado no Continuation\<TFail, TSuccess> independente de seu estado, com isso, evitando duplicar código nos métodos Then e Catch.                                                                                                                                                                                                                       |
| Merge   | Func\<TSuccess, Continuation\<TNewFail,TNewSuccess>> mergeMethod                                                    | Continuation<( Option\<TFail>, Option\<TNewFail>), (TSuccess, TNewSuccess)> | Permite uma maneira de unir dois diferentes Continuations em um único, onde os valores são agrupados em tuplas: Continuation<(TFail, TNewFail), (TSuccess, TNewSuccess)>.                                                                                                                                                                                                                                      |

## Sobrecargas de operadores

| Operador                     | Parâmetros                                                                                                          | Retorno                        | Descrição                                                                                                                                                                                                                                                  |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Cast implícito               | TSuccess success                                                                                                    | Continuation\<TFail, TSuccess> | Inicializa uma nova instância de um valor Continuation com o estado IsSuccess encapsulando o valor informado no parâmetro.                                                                                                                                 |
| Cast implícito               | TFail fail                                                                                                          | Continuation\<TFail, TSuccess> | Inicializa uma nova instância de um valor Continuation com o estado IsFail encapsulando o valor informado no parâmetro.                                                                                                                                    |
| Cast implícito               | Continuation\<TFail, TSuccess>                                                                                      | Option\<TFail>                 | <p>Permite a criação de um valor Option&#x3C;TFail> através de um cast implícito de um valor Continuation.</p><p>Caso o valor Continuation esteja no estado IsFail será criado um valor opcional no estado IsSome.</p>                                     |
| Cast implícito               | Continuation\<TFail, TSuccess>                                                                                      | Option\<TSuccess>              | <p>Permite a criação de um valor Option&#x3C;TSuccess> através de um cast implícito de um valor Continuation.</p><p>Caso o valor Continuation esteja no estado IsSuccess será criado um valor opcional no estado IsSome.</p>                               |
| Cast implícito               | Either\<TFail, TSuccess>                                                                                            | Continuation\<TFail, TSuccess> | <p>Permite a criação de um valor Continuation&#x3C;TRight> através de um cast implícito de um valor Either.</p><p>Caso o valor Either esteja no estado IsLeft será criado um valor Continuation no estado IsFail, caso contrário, no estado IsSuccess.</p> |
| Operador maior (>)           | <p>Continuation&#x3C;TFail, TSuccess></p><p>Func&#x3C;TSuccess, Continuation&#x3C;TFail, TSuccess>> thenMethod</p>  | Continuation\<TFail, TSuccess> | Executa o método Then para realizar o pipeline através do operador.                                                                                                                                                                                        |
| Operador maior ou igual (>=) | <p>Continuation&#x3C;TFail, TSuccess></p><p>Func&#x3C;TSuccess, Continuation&#x3C;TFail, TSuccess>> catchMethod</p> | Continuation\<TFail, TSuccess> | Executa o método Catch para realizar o pipeline através do operador.                                                                                                                                                                                       |

> &#x20;**Atenção**&#x20;
>
> Por conta de obrigações da linguagem este tipo também implementa os operadores menor (`<`) e menor ou igual (`<=`). Mas caso qualquer um dos dois seja utilizado, a biblioteca irá lançar a exceção [`NotSupportedException`](https://msdn.microsoft.com/pt-br/library/system.notsupportedexception\(v=vs.110\).aspx).

## Como Usar

Você pode criar um valor do tipo `Continuation` de várias formas diferentes, geralmente a criação de um `Continuation` indica que uma série de funções serão executadas a seguir.

Os modos de criação de um `Continuation` são bastante semelhantes à criação de um valor `Either`:

### Criando valores Continuation

Você pode utilizar o construtor para criar valores contendo o estado `IsFail` ou `IsSuccess` de acordo com o parâmetro, conforme código:

**Utilizando o construtor**

```csharp
Continuation<bool, int> valueWithRight = new Continuation<bool, int>(10); //-> IsSuccess
Continuation<bool, int> valueWithLeft = new Continuation<bool, int>(false); //-> IsFail
```

Você também pode utilizar o método _estático_ `Return`.

**Utilizando o método&#x20;**_**estático**_**&#x20;Return**

```csharp
Continuation<bool, int> valueWithRight = Continuation<bool, int>.Return(10); //-> IsSuccess
Continuation<bool, int> valueWithLeft = Continuation<bool, int>.Return(false); //-> IsFail
```

E como os tipos anteriores descritos nesta seção, também há as sobrecargas de cast implícito onde não é necessário se preocupar com nenhum tipo de sintaxe, basta criar o valor de um dos dois tipos `TFail` ou `TSuccess` declarado e a linguagem fará todo o trabalho.

&#x20;**Utilizando cast implícito**

```csharp
Continuation<bool, int> valueWithRight = 10;   //-> IsSuccess
Continuation<bool, int> valueWithLeft = false; //-> IsFail
```

Através deste cast implícito, você poderá gerar novos métodos para retornar o tipo `Continuation` em sua aplicação sem alterar nada no corpo especial da função, apenas indicando que a função retorna um valor deste tipo. Assim como no `Either` é possível informar duas instruções de return com tipos **diferentes**.

Veja este exemplo:

```csharp
private Continuation<string, int> GetSquareIfEven(int value)
{
  if (value % 2 == 0)
    return value * value;
  else
    return "Odd";
}
```

### Obtendo informação de um valor Continuation

Assim como nos valores `Either` e `Option`, a informação armazenada em um `Continuation` está encapsulada. Para obter a informação de um `Continuation` é necessário realizar um cast implícito para um valor opcional para `TFail` ou `TSuccess` ou utilizarmos o método `Match`.

Caso o tipo identificado pelo `Option` seja o tipo referente ao estado atual do valor `Continuation` será gerado um valor opcional no estado `IsSome`, caso contrário será gerado no estado `IsNone`.

&#x20;**Utilizando o cast implícito para Option**&#x20;

```csharp
Continuation<bool, int> continuationValue = 10;
Option<int> optionValue = continuationValue;

//optionValue.IsSome = true
//optionValue.IsNone = false
```

```csharp
Continuation<bool, int> continuationValue = 10;
Option<bool> optionValue = eitherValue;

//optionValue.IsSome = false
//optionValue.IsNone = true
```

> &#x20;**Atenção**&#x20;
>
> Mesmo realizando o cast implícito para o tipo correto, podem haver casos onde o valor opcional esteja no estado IsNone.
>
> Esta situação ocorre quando o valor armazenado no tipo Continuation é igual ao valor `default` ou igual à `null`.

```csharp
Continuation<bool, int> continuationValue = 0;
Option<int> optionValue = eitherValue;

//optionValue.IsSome = false
//optionValue.IsNone = true
```

O método `Match` disponível nesta estrutura funciona da mesma maneira que os métodos `Match` disponíveis em `Option` e `Either`.

Os métodos `Match` esperam dois métodos por parâmetro, estes métodos podem realizar transformações no valor `Continuation`, ou apenas retorná-los, conforme exemplos a seguir.

&#x20;**Utilizando Match com parâmetros nomeados**

```csharp
Continuation<bool, int> continuationValue = 10;
int value = continuationValue.Match(
        methodWhenSuccess: success => success,
        methodWhenFail: fail => 0);

//value = 10
```

O primeiro método será executado apenas se o valor `Continuation` estiver no estado `IsSuccess`, logo, este método recebe um valor do tipo que representa sucesso por parâmetro, `int`, no exemplo.

O segundo método recebe um valor do tipo que representa uma falha, `bool`, mas note que ambos precisam retornar valores do mesmo tipo. Portanto, foi utilizado o valor zero (0) para seguir o fluxo da aplicação caso o `Continuation` esteja no estado `IsFail`.

Não há necessidade de nomear os métodos, basta utilizá-los na ordem correta.

&#x20;**Utilizando Match**&#x20;

```csharp
Continuation<bool, int> continuationValue = 10;
int value = continuationValue.Match(
         success => success,
         fail => 0);

//value = 10
```

Além disso, você também pode aplicar algum tipo de transformação no valor no momento de obtê-lo, como por exemplo, elevá-lo ao quadrado.

```csharp
Continuation<bool, int> continuationValue = 10;
int value = continuationValue.Match(
        success => success * success,
        fail => 0);

//value = 100
```

Você também pode retornar o valor que precisar para o caso do estado ser `IsFail`, nos exemplos anteriores foi utilizado o valor zero, mas não há nenhuma obrigatoriedade nisso.

O método Match também não precisa retornar nenhum dos dois tipos do `Continuation`.

&#x20;**Utilizando Match para retornar um novo valor**&#x20;

```csharp
Continuation<bool, int> continuationValue = 10;
string value = continuationValue.Match(
        success => success.ToString(),
        fail    => fail.ToString());

//value = "10"
```

```csharp
Continuation<bool, int> continuationValue = true;
string value = continuationValue.Match(
        success => success.ToString(),
        fail    => fail.ToString());

//value = "true"
```

Não há a possibilidade de comparar dois valores `Continuation` ao mesmo tempo, este tipo não implementa o método `Match2` por não fazer parte de seu contexto.

## Criando Pipelines de Execução

O real valor do tipo `Continuation` está em sua capacidade de gerar métodos sofisticados e limpos através de operações em pipeline com os métodos `Then` e `Catch`.

Neste primeiro exemplo iremos apenas alterar um valor inteiro somando-o com cinco e depois com dez.

&#x20;**Utilizando o Then para alterar o valor**&#x20;

```csharp
Continuation<bool, int> continuation = 5;
Option<int> optionResult = 
    continuation.Then(value => value + 5)
                .Then(value => value + 10);

//optionResult.IsSome = true
//optionResult.Some = 20
```

O objeto `continuation` inicialmente continha o valor 5, após executarmos o primeiro método `Then` o processamento é feito e o valor armazenado (5) é passado como parâmetro para a função anônima: `value => value + 5`.

Por fim, o resultado desta operação (10) é passado como parâmetro para a segunda função anônima: `value => value + 10`, produzindo o resultado final (20).

### Quando o Then não é executado

Caso o `continuation` esteja no estado `IsFail` nenhum dos métodos `Then` é executado. Ocorre apenas um bypass do valor.

```csharp
Continuation<bool, int> continuation = true;
Option<int> optionResult = 
    continuation.Then(value => value + 5)
                .Then(value => value + 10);

//optionResult.IsSome = false
//optionResult.IsNone = true
```

Neste caso, podemos obter o resultado utilizando um `Option<bool` para mapear a falha.

&#x20;**Utilizando cast implícito para obter a falha**&#x20;

```csharp
Continuation<bool, int> continuation = true;
Option<bool> optionResult = 
    continuation.Then(value => value + 5)
                .Then(value => value + 10);

//optionResult.IsSome = true
//optionResult.Some = true
```

Um ponto importante a ser ressaltado é a possibilidade de uma das funções utilizadas em pipeline retornar o tipo referente à falha. Caso isso ocorra todos os métodos `Then` após ela serão ignorados.

&#x20;**Quando a falha ocorre no meio do caminho**&#x20;

```csharp
Continuation<bool, int> continuation = 5;
Option<int> optionResult = 
    continuation.Then(value => value + 4)
                .Then(value => 
                      {
                        if( value % 2 == 0)
                            return value + 5;
                        else
                            return false;
                      })
                .Then(value => value + 10);

//optionResult.IsSome = false
```

No exemplo anterior, a falha ocorre somente no segundo `Then`, isso significa que o `Then` que o antecede executa normalmente, mas o `Then` que vem depois não será executado.

Para criar métodos que lidem com os erros, é necessário utilizar o método `Catch`.

### Utilizando o Catch para tratar erros

Quando um `Continuation` está no valor `IsFail` os métodos `Then` não serão executados, eles apenas passarão o valor para o próximo método, até encontrar um método `Catch`.

```csharp
Continuation<string, int> continuation = 5;
Option<string> optionResult = 
    continuation.Then(value => value + 4)
                .Then(value => 
                      {
                        if( value % 2 == 0)
                            return value + 5;
                        else
                            return "ERROR";
                      })
                .Then(value => value + 10)
                .Catch(fail => $"{fail} catched");

//optionResult.IsSome = true
//optionResult.Some = "ERROR catched"
```

Assim como o método `Then` também é possível executar diversos métodos `Catch` de forma encadeada.

&#x20;**Catches encadeados**&#x20;

```csharp
Continuation<string, int> continuation = 5;
Option<string> optionResult = 
    continuation.Then(value => value + 4)
                .Then(value => 
                      {
                        if( value % 2 == 0)
                            return value + 5;
                        else
                            return "ERROR";
                      })
                .Then(value => value + 10)
                .Catch(fail => $"{fail} catched")
                .Catch(message => $"{message} again")
                .Catch(message => $"{message} and again");

//optionResult.IsSome = true
//optionResult.Some = "ERROR catched again and again"
```

### Evite repetição de código com o Finally

Em alguns casos é necessário executar uma determinada ação independente do resultado contido no `Continuation`. Esta é a função principal do método `Finally`, funciona de maneira similar ao `Then` e ao `Catch`, mas neste caso, a função sempre é executada.

Outra diferença clara entre o `Finally` e os dois anteriores é a função recebida por parâmetro. Neste caso, você pode utilizar uma função que não recebe nenhum parâmetro.

Ela será executada e depois disso, o `Continuation` será retornado novamente para manter o fluxo contínuo.

```csharp
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();

ContinuationModule.Resolve(5)
                  .Then(value => value + 4)
                  .Then(value => value + 10)
                  .Catch(fail => $"{fail} catched")
                  .Finally(() => stopwatch.Stop());
```

Apesar de não ser obrigatório, o `Finally` geralmente é a última chamada do fluxo de um `Continuation`, além disso, é comum este método causar algum efeito colateral, portanto, seja cuidadoso.

Outra particularidade deste método é o fato de que ele não é capaz de modificar o valor armazenado no `Continuation`. Na verdade, é possível **acessar** o valor armazenado usando a sobrecarga que recebe um `Action<Either<TFail, TSuccess>>` como parâmetro.

```csharp
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();

ContinuationModule.Resolve<string, int>(5)
                  .Then(value => value + 4)
                  .Then(value => value + 10)
                  .Catch(fail => $"{fail} catched")
                  .Finally(values => Console.WriteLine(
                      values.Match(
                        number => number.ToString(), 
                        text => text)));
```

Assim como o `Then` e o `Catch`, o método `Finally` também permite encadeamentos.

### Unindo dois Continuations diferentes em um novo

Esta não é uma operação comum, mas existem casos onde você precisa unir duas pipelines de valores `Continuation` diferentes para completar alguma determinada tarefa. Para facilitar este processo, você pode utilizar o método `Merge`.

A função recebida por parâmetro por este método recebe o próprio `Continuation<TFail, TSuccess>` por parâmetro e deve retornar um novo `Continuation<TNewFail, TNewSuccess>`. Depois disso, o retorno do `Merge` é criado agrupando os dois em um novo: `Continuation<(Option<TFail>, Option<TNewFail>), (TSuccess, TNewSuccess)>`

O continuation gerado pelo `Merge` estará no estado de `Success` somente quando os dois anteriores também estiverem, nos outros casos, o novo `Continuation` estará no estado `Fail`.

Você pode continuar seu fluxo normalmente, mas depois de chamar este método será necessário acessar as propriedades `Item`, afinal os valores foram agrupados em tuplas.

```csharp
Continuation<bool, double> continuation2 = 28.5;
ContinuationModule.Resolve<string, int>(10)
                  .Then(value => value + 2)
                  .Merge(value => continuation2)
                  .Then(values => values.Item1 + values.Item2)
                  .Match(value => value, _ => 0);
```

Note que os tipos de falha do novo `Continuation` são tratados como valores opcionais, porque não há garantia de qual dos erros ocorreu.

### Encadeando métodos com o operador de pipeline

A linguagem funcional da plataforma .NET, o F#, possui um operador para realizar pipelines, este operador é definido por: `|>` para pipe-foward e `<|` para reverse pipe ou pipe-backward.

Com eles podemos realizar operações na linguagem F# como estas:

```fsharp
let append1 string1 = string1 + ".append1"
let append2 string1 = string1 + ".append2"

let result1 = "abc" |> append1
printfn "\"abc\" |> append1 gives %A" result1

let result2 = "abc" 
              |> append1
              |> append2
printfn "result2: %A" result2

[1; 2; 3]
|> List.map (fun elem -> elem * 100)
|> List.rev
|> List.iter (fun elem -> printf "%d " elem)
printfn ""
```

Infelizmente não há como criar novos operadores no C# até a versão atual. No entanto, é possível sobrescrever os operadores existentes.

Pensando nisso, realizei a sobrescrita dos operadores `>` e `>=` para funcionarem de forma similar ao pipe-foward do F#.

Ao invés de realizarem as comparações de maior e maior ou igual, os operadores atuam recebendo como parâmetro um delegate `Func` idêntico aos utilizados nos métodos `Then` e `Catch`.

Por tanto é possível realizar as operações em pipeline substituindo as chamadas ao método `Then` pelo operador `>` e as chamadas ao método `Catch` pelo operador `>=`.

&#x20;**Utilizando o operador `>` para Then**&#x20;

```csharp
Continuation<bool, int> continuation = 5;
Option<int> optionResult = 
    continuation 
    > (value => value + 5)
    > (value => value + 10)
    > (value => value + 10)


//optionResult.IsSome = true
//optionResult.Some = 30
```

&#x20;**Utilizando os operadores `>` e `>=` para Then e Catch**

```csharp
Continuation<string, int> continuation = 5;
Option<string> optionResult = 
    continuation 
    >  (value => value + 4)
    >  (value => 
       {
          if( value % 2 == 0)
              return value + 5;
          else
              return "ERROR";
       })
    >  (value => value + 10)
    >= (fail => $"{fail} catched")
    >= (message => $"{message} again")
    >= (message => $"{message} and again");

//optionResult.IsSome = true
//optionResult.Some = "ERROR catched again and again"
```

> &#x20;**Atenção**&#x20;
>
> Há uma limitação na utilização dos operadores. 1. Não há uma versão possível do pipe-backward 2. É possível utilizar o operador somente nos métodos que retornam um valor do mesmo tipo que seu parâmetro, diferente dos métodos `Then` e `Catch` não há como sobrecarregar os parâmetros com _generics_.

### Quando o tipo do valor é alterado durante os métodos

Os dois métodos para realizar pipelines possuem sobrecargas para alterar o tipo do valor armazenado no `Continuation`, desta forma é possível transformar o valor ao longo da execução.

&#x20;**Alterando o tipo do Continuation durante as execuções**&#x20;

```csharp
Continuation<object, int> continuation = 10;
Option<string> optionResult =
    continuation
    .Then<bool>(value => value % 2 == 0)
    .Then<string>(value => value ? "Even" : "Odd");

//optionResult.IsSome = true
//optionResult.Some = "Even"
```

Note que para alterar o tipo não é necessário utilizar a notação de _generics_ `Then<tipoDestino>`, mas você pode explicitá-lo se quiser. O mesmo ocorre com o método `Catch`.

&#x20;**Alterando diversas vezes os tipos**&#x20;

```csharp
Continuation<string, int> continuation = 1;

Option<double> optionResult =
    continuation
    .Then<bool>(value =>
    {
        if (value % 2 == 0)
            return true;
        else
            return "Life, the Universe and Everything";
    })
    .Catch<double>(message => 42.0);

//optionResult.IsSome = true
//optionResult.Some = 42.0
```

### Quando é necessário unir os resultados em um único tipo

Quando é necessário unificar as duas possibilidades de valores em um `Continuation` é sugerido utilizar o método `Match` após todas as execuções.

```csharp
Continuation<bool, int> continuation = 5;
int integerResult = 
    continuation.Then(value => value + 4)
                .Then(value => 
                      {
                        if( value % 2 == 0)
                            return value + 5;
                        else
                            return false;
                      })
                .Then(value => value + 10)
                .Match(success => success,
                       fail    => 0);

//integerResult  = 0
```

Assim como nos outros tipos você pode utilizar o `Match` para retornar qualquer tipo, desde que ambos os métodos o retornem.
