Partilhar via


Expressões de computação (F#)

As expressões de computação no F# fornecem uma sintaxe conveniente para escrever as computações que podem ser seqüenciadas e combinados usando construções de fluxo de controle e ligações. Eles podem ser usados para fornecer uma sintaxe conveniente para mônadas, um recurso de programação funcional que pode ser usado para gerenciar dados, controle e os efeitos colaterais em programas funcionais.

Fluxos de trabalho internos

As expressões de seqüência são um exemplo de uma expressão de cálculo, como fluxos de trabalho assíncrono. Para obter mais informações sobre expressões de seqüência, consulte seqüências. Para obter mais informações sobre os fluxos de trabalho assíncronos, consulte Fluxos de trabalho assíncronos.

Certos recursos são comuns para expressões de seqüência e de fluxos de trabalho assíncronos e ilustram a sintaxe básica para uma expressão de cálculo:

builder-name { expression }

A sintaxe anterior Especifica que a expressão especificada é uma expressão de cálculo de um tipo especificado por builder-name. A expressão de cálculo pode ser um fluxo de trabalho interno, como seq ou async, ou pode ser algo que você definir. O builder-name o identificador para uma instância de um tipo especial conhecido como o o tipo de construtor. O tipo de construtor é um tipo de classe que define métodos especiais que controlam a maneira como os fragmentos da expressão de cálculo são combinados, ou seja, código que controla como a expressão é executada. Outra maneira de descrever uma classe de construtor é dizer que ele permite que você personalize a operação de muitas F# construções, como loops e ligações.

Em expressões de computação, os dois formulários estão disponíveis para algumas construções de linguagem comum. Você pode chamar as construções de variant usando um! (Pronto) sufixo em determinadas palavras-chave, como let!, do!e assim por diante. Esses formulários especiais causam determinadas funções definidas na classe de construtor para substituir o comportamento interno comum dessas operações. Esses formulários se assemelhem a yield! forma do yield palavra-chave que é usado em expressões de seqüência. Para obter mais informações, consulte seqüências.

Criando um novo tipo de expressão de cálculo

Você pode definir as características de suas próprias expressões de computação, criando uma classe de construtor e definindo o determinados métodos especiais na classe. A classe de construtor opcionalmente pode definir os métodos, conforme listado na tabela a seguir.

A tabela a seguir descreve os métodos que podem ser usados em uma classe de construtor de fluxo de trabalho.

Método

Típica nomeada

Descrição

Bind

M<'T> * ('T -> M<'U>) -> M<'U>

Chamado para let! e do! em expressões de computação.

Delay

(unit -> M<'T>) -> M<'T>

Uma expressão de cálculo como uma função de quebra.

Return

'T -> M<'T>

Chamado para return em expressões de computação.

ReturnFrom

M<'T> -> M<'T>

Chamado para return! em expressões de computação.

Run

M<'T> -> M<'T>ou

M<'T> -> 'T

Executa uma expressão de cálculo.

Combine

M<'T> * M<'T> -> M<'T>ou

M<unit> * M<'T> -> M<'T>

Chamado para o seqüenciamento em expressões de computação.

For

seq<'T> * ('T -> M<'U>) -> M<'U>

Chamado para for...do expressões em expressões de computação.

TryFinally

M<'T> * (unit -> unit) -> M<'T>

Chamado para try...finally expressões em expressões de computação.

TryWith

M<'T> * (exn -> M<'T>) -> M<'T>

Chamado para try...with expressões em expressões de computação.

Using

'T * ('T -> M<'U>) -> M<'U> when 'U :> IDisposable

Chamado para use ligações em expressões de computação.

While

(unit -> bool) * M<'T> -> M<'T>

Chamado para while...do expressões em expressões de computação.

YieldFrom

M<'T> -> M<'T>

Chamado para yield! expressões em expressões de computação.

Zero

unit -> M<'T>

Chamado para vazio else ramificações da if...then expressões em expressões de computação.

Muitos dos métodos em uma classe de construtor de fluxo de trabalho usar e retornar um M<'T> Construir, que é geralmente um tipo definido separadamente que caracteriza o tipo de computações sendo combinado, por exemplo, Async<'T> para fluxos de trabalho assíncronos e Seq<'T> para a seqüência de fluxos de trabalho. As assinaturas dos métodos a seguir permitem ser combinados e aninhados uns com os outros, para que o objeto de fluxo de trabalho retornado de uma construção que pode ser passado para o próximo. O compilador, quando ele analisa uma expressão de cálculo, converte a expressão de uma série de chamadas de função aninhada usando os métodos na tabela anterior e o código da expressão de cálculo.

A expressão aninhada é da seguinte forma:

builder.Run(builder.Delay(fun () -> {| cexpr |}))

No código acima, as chamadas para Run e Delay são omitidos se não forem definidos no construtor de expressão de computação classe. O corpo da expressão de cálculo, aqui indicada como {| cexpr |}, que é traduzido em chamadas envolvendo os métodos da classe builder por traduções descritos na tabela a seguir. A expressão de computação {| cexpr |} é recursivamente definido de acordo com a essas traduções onde expr é uma expressão de F# e cexpr é uma expressão de cálculo.

Expression

Tradução

{| let binding in cexpr |}

let binding in {| cexpr |}

{| let! pattern = expr in cexpr |}

builder.Bind(expr, (fun pattern -> {| cexpr |}))

{| do! expr in cexpr |}

builder.Bind(expr1, (fun () -> {| cexpr |}))

{| yield expr |}

builder.Yield(expr)

{| yield! expr |}

builder.YieldFrom(expr)

{| return expr |}

builder.Return(expr)

{| return! expr |}

builder.ReturnFrom(expr)

{| use pattern = expr in cexpr |}

builder.Using(expr, (fun pattern -> {| cexpr |}))

{| use! value = expr in cexpr |}

builder.Bind(expr, (fun value -> builder.Using(value, (fun value -> {| cexpr |}))))

{| if expr then cexpr0 |}

if expr then {| cexpr0 |} else binder.Zero()

{| if expr then cexpr0 else cexpr1 |}

if expr then {| cexpr0 |} else {| cexpr1 |}

{| match expr with | pattern_i -> cexpr_i |}

match expr with | pattern_i -> {| cexpr_i |}

{| for pattern in expr do cexpr |}

builder.For(enumeration, (fun pattern -> {| cexpr }|))

{| for identifier = expr1 to expr2 do cexpr |}

builder.For(enumeration, (fun identifier -> {| cexpr }|))

{| while expr do cexpr |}

builder.While(fun () -> expr), builder.Delay({|cexpr |})

{| try cexpr with | pattern_i -> expr_i |}

builder.TryWith(builder.Delay({| cexpr |}), (fun value -> match value with | pattern_i -> expr_i | exn -> reraise exn)))

{| try cexpr finally expr |}

builder.TryFinally(builder.Delay( {| cexpr |}), (fun () -> expr))

{| cexpr1; cexpr2 |}

builder.Combine({|cexpr1 |}, {| cexpr2 |})

{| other-expr; cexpr |}

expr; {| cexpr |}

{| other-expr |}

expr; builder.Zero()

Na tabela anterior, other-expr descreve uma expressão que não está listada na tabela. Uma classe de construtor não precisa implementar todos os métodos e oferecer suporte a todas as traduções listadas na tabela anterior. Essas construções que não são implementadas não estão disponíveis em expressões de computação desse tipo. Por exemplo, se você não deseja oferecer suporte a use palavra-chave em suas expressões de computação, você pode omitir a definição de Use na sua classe de construtor.

O exemplo de código a seguir ilustra a criação e o uso de um tipo de expressão de cálculo simples que gera algumas saídas de console que acompanha o andamento da execução de código.

// Program.fs
open Module1

// Create the computation expression object.
let trace1 = trace {
   // A normal let expression (does not call Bind).
   let x = 1
   // A let expression that uses the Bind method.
   let! y = 2
   let sum = x + y
   // return executes the Return method.
   return sum  
   }

// Execute the code. Start with the Delay method.
let result = trace1()

O código a seguir implementa a classe de construtor para a expressão de cálculo de rastreamento.

// Module1.fs
module Module1 =

 // Functions that implement the builder methods.
 let bind value1 function1 = 
     printfn "Binding %A." value1 
     function1 value1

 let result value1 =
     printfn "Returning result: %A" value1
     fun () -> value1

 let delay function1 =
     fun () -> function1()

 // The builder class for the "trace" workflow.
 type TraceBuilder() =
     member x.Bind(value1, function1) = 
         bind value1 function1
     member x.Return(value1)  = result value1
     member x.Delay(function1)   = 
         printfn "Starting traced execution."
         delay function1

 let trace = new TraceBuilder()

A saída deste exemplo é o seguinte.

Starting traced execution.
Binding 2.
Returning result: 3

Consulte também

Outros recursos

Referência de linguagem do F#

Histórico de alterações

Date

History

Motivo

Dezembro de 2010

Adicionado Run método e a tabela de traduções.

Comentários do cliente.