Este artigo foi traduzido por máquina.

Fundamentos do F#

Uma introdução à programação funcional para desenvolvedores do .NET

Chris Marinos

Baixe o código de exemplo

Por enquanto, há uma boa chance de que você já ouviu falar sobre o F #, a mais recente adição à família de idioma do Microsoft Visual Studio. Existem vários motivos interessantes para aprender a F # — sua sintaxe limpa, os recursos avançados de vários segmentos e sua interoperabilidade com outras linguagens do Microsoft .NET Framework fluida. No entanto, F # inclui alguns conceitos importantes novos que você precisará compreender antes você pode tirar proveito desses recursos.

Um tour rápido é uma boa maneira de começar a aprender outra linguagem orientada a objeto ou até mesmo uma linguagem dinâmica como Ruby ou Python. Isso ocorre porque você já conhece a maior parte do vocabulário e você precisa apenas aprender a nova sintaxe. F # é diferente, porém. F # é uma linguagem de programação funcional e com que vem vocabulário mais novo que você pode esperar. Além disso, as linguagens funcionais tradicionalmente foram usadas no meio acadêmico, portanto, as definições para esses novos termos podem ser difícil de entender.

Felizmente, F # não foi projetado para ser um idioma acadêmico. Sua sintaxe permite que você use funcionais técnicas para solucionar problemas de maneiras novas e melhores enquanto ainda suporta os estilos de imperativos e orientada a objeto que você está acostumados a como um desenvolvedor .NET. Ao contrário de outras linguagens. NET, F estrutura multi-paradigm da # significa que você está livres para escolher o estilo práticas de programação para o problema que você está tentando resolver. Programação funcional em F # é sobre como escrever códigos concisos e eficientes para solucionar problemas práticos de software. É sobre como usar técnicas, como funções de ordem superior e a composição de função para criar poderosos e fáceis de entender comportamentos. Também é sobre como tornar seu código mais fácil de entender, testar e colocar em paralelo, removendo a complexidades ocultas.

Mas a fim de que você se beneficie de todos esses recursos fantásticos da F #, você precisa compreender os fundamentos. Neste artigo, vou explicar esses conceitos usando o vocabulário que você já estiver familiarizado com como um desenvolvedor .NET. Também mostrarei a você algumas técnicas de programação funcionais que você pode aplicar ao seu código existente e algumas maneiras em que você está já Programando funcionalmente. No final deste artigo, você saberá suficiente sobre a programação funcional para que você possa pegar ponta a ponta com F # no Visual Studio 2010.

Noções básicas de programação funcional

Para a maioria dos desenvolvedores .NET, é mais fácil entender é que a programação funcional Compreendendo o que não é. Programação imperativa é um estilo de programação é considerado como sendo o oposto da programação funcional. Também é o estilo de programação que você provavelmente está mais familiarizado com porque a maioria das linguagens de programação tradicionais são imperativa.

Programação funcional e programação imperativa diferem em um nível muito básico e você pode ver isso no mesmo código mais simples:

int number = 0;
number++;

Obviamente, isso incrementa uma variável por um. Que não é muito interessante, mas considere a possibilidade de maneira diferente que você pode resolver o problema:

const int number = 0;
const int result = number + 1;

O número é ainda incrementado em uma unidade, mas não é modificado no lugar. Em vez disso, o resultado é armazenado como outra constante porque o compilador não permite que você modifique o valor de uma constante. Você diria que constantes são imutáveis, porque não é possível alterar seus valores assim que elas são definidas. Por outro lado, a variável de número do meu primeiro exemplo foi mutável porque você pode modificar seu valor. Essas duas abordagens mostram uma das diferenças fundamentais entre programação imperativa e programação funcional. Programação imperativa enfatiza o uso de variáveis mutáveis enquanto programação funcional usa valores imutáveis.

A maioria dos desenvolvedores .NET diria que o número e o resultado no exemplo anterior são variáveis, mas como um programador funcional você precisa tomar mais cuidado. Afinal, a idéia de uma variável constante é confusa com melhor desempenho. Em vez disso, os programadores funcionais dizem que o número e o resultado são valores. Certifique-se de que você reservar a variável termo para objetos que são mutáveis. Observe que esses termos não são exclusivos para programação funcional, mas elas são muito mais importantes quando estiver programando em um estilo funcional.

Essa distinção pode parecer pequena, mas é a base para muitos conceitos que tornam a programação funcional tão poderoso. Mutáveis variáveis são a principal causa de muitos bugs desagradáveis. Como você verá abaixo, eles levam a dependências implícitas entre diferentes partes do seu código, que faz para muitos problemas, especialmente relacionados à simultaneidade. Por outro lado, as variáveis imutáveis apresentam significativamente menos complexidade. Eles levam a técnicas funcionais como usando funções como valores e composicional programação que vou também explorar em mais detalhes posteriormente.

Se você tiver dúvidas de programação funcional neste momento, Don se preocupe. É natural. Os programadores mais imperativos são treinados para acreditar que não é nada útil com valores imutáveis. No entanto, considere este exemplo:

string stringValue = "world!";
string result = stringValue.Insert(0, "hello ");

A função inserir parte a seqüência de caracteres de “ Olá mundo! ”, mas você sabe que inserir não modifica o valor da seqüência de caracteres de origem. Isso ocorre porque as seqüências de caracteres são imutáveis no. NET. Os designers do .NET Framework usada uma abordagem funcional porque ele tornou fácil escrever códigos melhores com seqüências de caracteres. Como seqüências de caracteres estão entre os tipos de dados mais amplamente usados no .NET Framework (juntamente com outros base tipos, como números inteiros, DateTimes e assim por diante), que há uma boa chance de você fez mais útil a programação funcional que você perceber.

Colocando F # em funcionamento

F # vem com o Visual Studio 2010, e você pode encontrar a versão mais recente em msdn.microsoft.com/vstudio. Se você usar o Visual Studio 2008, você poderá baixar um F # suplemento do F # Developer Center em MSDN.Microsoft.com/fsharp, onde você também encontrará as instruções de instalação para mono.

F # adiciona que uma nova janela para o Visual Studio chamada F # Interactive que unsurprisingly, permite executar código F # interativamente. Você pode considerá-la como uma versão mais potente da janela imediata que você pode acessar até mesmo quando não estiver no modo de depuração. Se você estiver familiarizado com Ruby ou Python, irá reconhecer que a F # Interactive é uma impressão avaliar leitura REPL (loop), que é uma ferramenta útil que para aprender a F # e testar rapidamente com o código.

Usarei F # Interactive neste artigo para mostrar o que acontece quando o exemplo de código é compilado e executado. Se você realçar código no Visual Studio e pressione ALT+ENTER, você envia o código para F # Interactive. Para ver isso, aqui está o exemplo de adição simples em F #:

let number = 0
let result = number + 1

Quando você executa esse código em F # Interactive, você obtém o seguinte:

val number : int = 0
val result : int = 1

Você provavelmente pode adivinhar, o termo val que numerar e resultar são os dois valores imutáveis, não mutáveis variáveis. Você pode ver isso usando <-, o operador de atribuição do F #:

> number <- 15;;

  number <- 15;;
  ^^^^^^^^^^^^

stdin(3,1): error FS0027: This value is not mutable
>

Como você sabe que a programação funcional se baseia em imutabilidade, esse erro deve fazer sentido. A palavra-chave permitem que é usada para criar ligações imutáveis entre os nomes e valores. Em termos de translation from VPE for Csharp, tudo o que é const por padrão em F #. Você pode fazer uma variável mutável se desejar, mas você tem que explicitamente disse. Os padrões são exatamente o oposto do qual você está familiarizado no linguagens imperativas:

let mutable myVariable = 0
myVariable <- 15

Inferência de tipo e sensibilidade de espaço em branco

F # permite declarar variáveis e valores sem especificar o tipo, para que você pode presumir que F # é uma linguagem dinâmica, mas isso não é verdadeiro. É importante entender que F # é uma linguagem estática como translation from VPE for Csharp ou C++. No entanto, F # tem um sistema de inferência de tipos poderosa que permite que você evite especificar os tipos de objetos em vários locais. Isso permite uma sintaxe sucinta e simples, embora ainda ofereçam a segurança de tipo de linguagens estáticas.

Embora os sistemas de inferência de tipo como esse realmente não são encontrados no linguagens imperativas, inferência de tipo não está diretamente relacionada à programação funcional. No entanto, inferência de tipo é uma noção crítica para compreender se você deseja aprender a F #. Felizmente, se você for um desenvolvedor translation from VPE for Csharp, provavelmente que já estiver familiarizado com a inferência de tipo básico por causa da palavra-chave var:

// Here, the type is explictily given
Dictionary<string, string> dictionary = 
  new Dictionary<string, string>();

// but here, the type is inferred
var dictionary = new Dictionary<string, string>();

As duas linhas de código translation from VPE for Csharp criam novas variáveis que são digitadas como Dictionary < string, string > estaticamente, mas a palavra-chave var informa ao compilador para inferir o tipo da variável para você. F # leva esse conceito para o próximo nível. Por exemplo, eis uma função de adição em F #:

let add x y =
    x + y
    
let four = add 2 2

Não há uma anotação de tipo simples no código acima, mas F # 
Interactive revela digitação estática:

val add : int -> int -> int
val four : int = 4

Explicarei as setas em mais detalhes posteriormente, mas para agora você pode interpretar isso significa adicionar é definida para assumir dois argumentos int e que quatro é um valor int. O compilador F # foi capaz de inferir isso com base na forma como adicionar e quatro foram definidos. As regras que o compilador usa para fazer isso estão além do escopo deste artigo, mas você poderá aprender mais sobre eles no F # Developer Center se estiver interessado.

Inferência de tipo é uma maneira que F # reduz o ruído em seu código, mas observe que não existem chaves ou palavras-chave para indicar o corpo ou valor de retorno do Adicionar função. Isso ocorre porque a linguagem F # é uma linguagem de diferenciação de espaço em branco por padrão. No F #, indicam o corpo de uma função pelo recuo e retornar um valor, certificando-se de que ele é a última linha na função. Como inferência de tipos, sensibilidade de espaço em branco não tem relação direta para programação funcional, mas você precisa estar familiarizado com o conceito para usar a F #.

Efeitos colaterais

Agora você sabe que a programação funcional é diferente da programação imperativa porque ela depende de valores imutáveis em vez de variáveis mutáveis, mas esse fato não é muito útil por si só. A próxima etapa é entender os efeitos colaterais.

Na programação imperativa, saída da função depende o argumento de entrada e o estado atual do programa. Na programação funcional, funções apenas dependem de seus argumentos de entrada. Em outras palavras, quando você chamar uma função mais de uma vez com o mesmo valor de entrada, você sempre obtém o mesmo valor de saída. O motivo pelo qual que isso não é verdade na programação imperativa é devido efeitos colaterais, como demonstrado no Figura 1.

Figura 1 Efeitos colaterais das variáveis mutável

public MemoryStream GetStream() {
  var stream = new MemoryStream();
  var writer = new StreamWriter(stream);
  writer.WriteLine("line one");
  writer.WriteLine("line two");
  writer.WriteLine("line three");
  writer.Flush();
  stream.Position = 0;
  return stream;
}

[TestMethod]
public void CausingASideEffect() {
  using (var reader = new StreamReader(GetStream())) {
    var line1 = reader.ReadLine();
    var line2 = reader.ReadLine();

    Assert.AreNotEqual(line1, line2);
  }
}

Na primeira chamada para ReadLine, o fluxo é ler até encontrar uma nova linha. Em seguida, ReadLine retornará todo o texto até a nova linha. Entre essas etapas, uma variável mutável que representa a posição do fluxo é atualizada. É o efeito colateral. Na segunda chamada ReadLine, o valor da variável mutável posição foi alterado, portanto ReadLine retorna um valor diferente.

Agora let’s examinar um dos mais importantes conseqüências de usando efeitos colaterais. Primeiro, considere uma classe simples PiggyBank e alguns métodos para trabalhar com ela (consulte Figura 2).

Figura 2 PiggyBanks mutáveis

public class PiggyBank{
  public PiggyBank(int coins){
    Coins = coins;
  }

  public int Coins { get; set; }
}

private void DepositCoins(PiggyBank piggyBank){
  piggyBank.Coins += 10;
}

private void BuyCandy(PiggyBank piggyBank){
  if (piggyBank.Coins < 7)
    throw new ArgumentException(
      "Not enough money for candy!", "piggyBank");

  piggyBank.Coins -= 7;
}

Se você tiver um banco de transporte com 5 moedas, você pode chamar DepositCoins antes BuyCandy, mas invertendo a ordem gerará uma exceção:

// this works fine
var piggyBank = new PiggyBank(5);

DepositCoins(piggyBank);
BuyCandy(piggyBank);

// but this raises an ArgumentException
var piggyBank = new PiggyBank(5);

BuyCandy(piggyBank);
DepositCoins(piggyBank);

A função BuyCandy e a função de DepositCoins ambos atualizar o estado do banco de transporte por meio do uso de um efeito colateral. Conseqüentemente, o comportamento de cada função depende do estado do banco de transporte. Como o número de moedas é mutável, a ordem na qual executar essas funções é significativa. Em outras palavras, há uma dependência de temporização implícito entre esses dois métodos.

Agora let’s tornar o número de moedas de leitura somente para simular uma estrutura de dados imutáveis. Figura 3 mostra que BuyCandy e DepositCoins agora retornam PiggyBank novos objetos, em vez de atualizar um PiggyBank existente.

Figura 3 PiggyBanks imutáveis

public class PiggyBank{
  public PiggyBank(int coins){
    Coins = coins;
  }

  public int Coins { get; private set; }
}

private PiggyBank DepositCoins(PiggyBank piggyBank){
  return new PiggyBank(piggyBank.Coins + 10);
}

private PiggyBank BuyCandy(PiggyBank piggyBank){
  if (piggyBank.Coins < 7)
    throw new ArgumentException(
      "Not enough money for candy!", "piggyBank");

  return new PiggyBank(piggyBank.Coins - 7);
}

Como antes, se você tentar chamar BuyCandy antes DepositCoins, você receberá uma exceção de argumento:

// still raises an ArgumentException
var piggyBank = new PiggyBank(5);

BuyCandy(piggyBank);
DepositCoins(piggyBank);

Mas agora, mesmo se você reverter a ordem, você terá o mesmo resultado:

// now this raises an ArgumentException,  too!
var piggyBank = new PiggyBank(5);

DepositCoins(piggyBank);
BuyCandy(piggyBank);

Aqui, BuyCandy e DepositCoins apenas dependem argumento de entrada porque o número de moedas é imutável. Você pode executar as funções em qualquer ordem e o resultado é o mesmo. A dependência de tempo implícita é perdida. No entanto, como você provavelmente deseja BuyCandy seja bem-sucedida, você precisa fazer com que o resultado do BuyCandy dependem da saída do DepositCoins. Você precisa fazer a dependência explícita:

var piggyBank = new PiggyBank(5);
BuyCandy(DepositCoins(piggyBank));

Essa é uma diferença sutil com conseqüências abrangente. Estado mutável compartilhado e as dependências implícitas são a origem de alguns bugs mais diabolical no código imperativo, e são o motivo que vários segmentos é tão difícil em linguagens imperativas. Você precisa se preocupar sobre a ordem na qual executar funções, você precisa contar com mecanismos de bloqueio complicados para manter as coisas reta. Puros programas funcionais são sem efeitos colaterais e dependências de tempo implícita, portanto, não importa a ordem na qual executar funções. Isso significa que você Don precisa se preocupar sobre mecanismos de bloqueio e outras técnicas de multithreading propensas a erros.

Mais fácil de vários segmentos é dos principais motivos que programação funcional está recebendo atenção ultimamente, mas há muitos outros benefícios da programação em um estilo funcional. Funções e sem efeito colateral são mais fácil de testar como a cada função depende somente de seus argumentos de entrada. Eles são mais fáceis de manter porque eles Don dependam implicitamente lógica de outras funções de configuração. Funções e sem efeito colateral também tendem a ser menores e mais fácil de combinar. Abordarei esse último ponto mais detalhadamente daqui a pouco.

No F #, você se concentrar na avaliação de funções para seus valores de resultado em vez de seus efeitos colaterais. Em linguagens imperativas, é comum para chamar uma função para fazer algo; em linguagens funcionais, as funções são chamadas para produzir um resultado. Você pode ver isso em F #, observando a se instrução:

let isEven x =
    if x % 2 = 0 then
        "yes"
    else
        "no"

Saiba que, no F #, a última linha de uma função é o valor de retorno, mas neste exemplo, a última linha da função é a se instrução. Isso não é um truque de compilador. No F #, mesmo se as instruções são projetadas para retornar valores:

let isEven2 x =
    let result = 
        if x % 2 = 0 then
            "yes"
        else
            "no"
    result

O valor de resultado é do tipo string e é atribuída diretamente para o se instrução. É semelhante à maneira como o operador condicional trabalha em translation from VPE for Csharp:

string result = x % 2 == 0 ? "yes" : "no";

O operador condicional enfatiza retornando um valor em fazendo com que um efeito colateral. É uma abordagem mais funcional. Em contraste, translation from VPE for Csharp se instrução for mais imperativa porque ele não retornará um resultado. Tudo o que ele pode fazer é causar efeitos colaterais.

Composição de funções

Agora que você viu alguns dos benefícios do lado do efeito livre funções, você está pronto para usar funções para todo o potencial em F #. Primeiro, iniciar let’s com algum código translation from VPE for Csharp para levar o quadrado dos números de zero até 10:

IList<int> values = 0.Through(10).ToList();

IList<int> squaredValues = new List<int>();

for (int i = 0; i < values.Count; i++) {
  squaredValues.Add(Square(values[i]));
}

Além do auxiliar Square e Through métodos, esse código é bastante padrão translation from VPE for Csharp. Bons desenvolvedores translation from VPE for Csharp provavelmente levaria umbrage com o uso de um loop for, em vez de um loop foreach e estiver corretamente. Linguagens modernas como loops de foreach translation from VPE for Csharp oferta como uma abstração para tornar a percorrer enumerações mais fácil, removendo a necessidade de indexadores explícitas. Eles bem-sucedida nesse objetivo, mas considere o código em Figura 4.

Figura 4 Uso de foreach loops

IList<int> values = 0.Through(10).ToList();

// square a list
IList<int> squaredValues = new List<int>();

foreach (int value in values) {
  squaredValues.Add(Square(value));
}

// filter out the even values in a list
IList<int> evens = new List<int>();

foreach(int value in values) {
  if (IsEven(value)) {
    evens.Add(value);
  }
}

// take the square of the even values
IList<int> results = new List<int>();

foreach (int value in values) {
  if (IsEven(value)) {
    results.Add(Square(value));
  }
}

Loops foreach neste exemplo são semelhantes, mas cada corpo do loop realiza uma operação de um pouco diferente. Programadores imperativos tradicionalmente foram algum problema com essa duplicação código porque foi considerada idiomatic código.

Os programadores funcionais adotam uma abordagem diferente. Em vez de criar abstrações como loops foreach para ajudar a orientá-lo listas, eles use livre de efeito colateral funções:

let numbers = {0..10}
let squaredValues = Seq.map Square numbers

Esse código F # também quadrados uma seqüência de números, mas ele faz isso usando uma função de ordem superior. Funções de ordem superior são simplesmente funções que aceitam outra função como um argumento de entrada. Nesse caso, a função Seq.map aceita o quadrado funcionar como um argumento. Ele se aplica esta função a cada número na seqüência de números e retorna a seqüência de números quadrados. Funções de ordem superior são por muitas pessoas dizem a programação funcional usa funções como dados. Isso significa apenas que funções podem ser usadas como parâmetros ou atribuídas a um valor ou variável como um inteiro ou uma seqüência de caracteres. Em termos de translation from VPE for Csharp, é muito semelhante aos conceitos de delegados e expressões lambda.

Funções de ordem superior são uma das técnicas que torna a programação funcional tão poderoso. Você pode usar funções de ordem superior para isolar o código duplicado dentro de loops foreach e encapsulá-lo em autônomas, funções e sem efeito colateral. Essas funções executam uma operação pequena que o código dentro de um loop foreach poderia ter manipulado. Como são livres de efeito colateral, você pode combinar essas funções para criar código mais legível, mais fácil de manter que realiza a mesma coisa que loops foreach:

let squareOfEvens = 
    numbers
    |> Seq.filter IsEven
    |> Seq.map Square

A parte somente confusa sobre este código pode ser o | > operador. Este operador é usado para tornar o código mais legível, permitindo que você reorganizar os argumentos para uma função para que o último argumento seja a primeira coisa que você ler. Sua definição é muito simples:

let (|>) x f = f x

Sem o | > operador, o código squareOfEvens teria esta aparência:

let squareOfEvens2 = 
  Seq.map Square (Seq.filter IsEven numbers)

Se você usar o LINQ, que utilize funções de ordem superior dessa maneira deve parecer bastante familiar. Isso ocorre porque o LINQ está profundamente enraizada na programação funcional. Na verdade, você pode converter facilmente o quadrado do problema de eventos em translation from VPE for Csharp usando métodos do LINQ:

var squareOfEvens =
  numbers
  .Where(IsEven)
  .Select(Square);

Isso se traduz na seguinte sintaxe de consulta LINQ:

var squareOfEvens = from number in numbers
  where IsEven(number)
  select Square(number);

Usando o LINQ no código translation from VPE for Csharp ou Visual Basic permite explorar alguns do poder da programação funcional em uma base diária. É uma maneira excelente para aprender técnicas de programação funcionais.

Quando você inicia a usar as funções de ordem superior regularmente, você eventualmente se deparar com uma situação na qual você desejar criar uma função pequena, muito específica para passar para uma função de ordem superior. Os programadores funcionais usar funções lambda para solucionar esse problema. Funções lambda são simplesmente funções que definem sem lhes dar um nome. Eles são normalmente pequenos e têm uma utilização muito específica. Por exemplo, há outra maneira que você poderia quadrado números pares usando um lambda:

let withLambdas =
    numbers
    |> Seq.filter (fun x -> x % 2 = 0)
    |> Seq.map (fun x -> x * x)

A única diferença entre esse e o código anterior aos números par quadradas é que o quadrado e IsEven são definidos como lambdas. No F #, você declara uma função lambda usando o divertido palavra-chave. Você só deve usar lambdas para declarar funções de uso único porque eles não podem ser usados facilmente fora do escopo em que eles são definidos. Por esse motivo, quadrado e IsEven são opções ruins para funções lambda porque eles são úteis em várias situações.

Aplicativo currying e parcial

Agora você sabe quase todos os conceitos básicos que necessários para iniciar o trabalho com F #, mas há um conceito mais que deve estar familiarizado. Nos exemplos anteriores, o | > operador e as setas no tipo de assinaturas da F # Interactive estão ligadas a um conceito conhecido como currying.

Currying significa a quebra de uma função com muitos argumentos em uma série de funções que cada levar um argumento e, por fim, produzem o mesmo resultado que a função original. Currying provavelmente é o tópico mais desafiador neste artigo para um desenvolvedor .NET, especialmente porque ele geralmente é confundido com o aplicativo parcial. Você pode ver ambos no trabalho neste exemplo:

let multiply x y =
    x * y
    
let double = multiply 2
let ten = double 5

Imediatamente, você deve ver o comportamento é diferente de linguagens imperativas mais. A segunda instrução cria uma nova função chamada dupla por passar um argumento para uma função que usa dois. O resultado é uma função que aceita um argumento int e produz a mesma saída como se tivesse chamado multiplicar com x igual a 2 e y igual ao argumento. Em termos de comportamento, é igual este código:

let double2 z = multiply 2 z

Muitas vezes, as pessoas por engano dizem que multiplique é curried ao formulário duplo. Mas isso só é um pouco true. A função de multiplicação é curried, mas o que acontece quando ele é definido como funções em F # são curried por padrão. Quando a função dupla é criada, é mais preciso dizer que a função de multiplicação é aplicada parcialmente.

Let’s ultrapassar estas etapas em mais detalhes. Currying divide uma função com muitos argumentos em uma série de funções que cada utilizam um argumento e, em última análise, produzem o mesmo resultado que a função original. A função de multiplicação possui a seguinte assinatura de tipo de acordo com a linguagem F # Interactive:

val multiply : int -> int -> int

Lá, descriptografados isso significa que multiplique é uma função que leva dois argumentos int e retorna um resultado int. Agora eu vai 
explain o que realmente acontece. A função de multiplicação é realmente uma série de duas funções. A função primeira tem um argumento int e retorna outra função, efetivamente ligação x para um valor específico. Essa função também aceita um argumento int que você pode pensar em como o valor para vincular a y. Depois de chamar essa segunda função, x e y são ambos vinculados, portanto, o resultado é o produto x e y conforme definido no corpo de duas vezes.

Para criar dupla, a primeira função da cadeia de funções de multiplicação é avaliada parcialmente aplicar multiplicar. A função resultante é dada a dobra de nome. Quando é avaliada duas vezes, ele usa seu argumento juntamente com o valor parcialmente aplicado para criar o resultado.

Usando o F # e programação funcional

Agora que você tem suficiente vocabulário para começar a F # e programação funcional, você tem várias opções para o que fazer em seguida.

F # Interactive permite explorar código F # e desenvolver rapidamente a linguagem F # scripts. Também é útil para validar diárias perguntas sobre o comportamento das funções de biblioteca do .NET sem recorrer para ajudar a arquivos ou pesquisas na Web.

F # se sobressai em expressar algoritmos complexos, portanto, você pode encapsular essas partes de seus aplicativos em bibliotecas F # podem ser chamados a partir de outras linguagens do. NET. Isso é especialmente útil em aplicativos de engenharia ou em situações de vários segmentos.

Finalmente, você pode usar técnicas de programação funcionais em seu desenvolvimento .NET diário sem até mesmo escrever código F #. Use LINQ em vez de para ou de loops foreach. Tente usar delegados para criar funções de ordem superior. Limite o uso de mutabilidadede e efeitos colaterais de sua programação imperativa. Quando você começa a escrever código em um estilo funcional, será mais mesmo que você estivesse escrevendo mais código F # em breve.

Chris Marinos é consultor de software Solutions SRT em Arbor Ana, Mich. É possível que ele ouvir falar sobre o F #, programação funcional e outros tópicos interessantes em eventos ao redor da área de Ana Maria Arbor ou em seu blog em srtsolutions.com/blogs/chrismarinos.

Graças aos seguintes especialistas técnicos para revisar este artigo: Luke Hoban