Pensamento funcional. Parte 2

Amigos, continuamos a entender programação funcional. Na segunda parte desta série de artigos, você aprenderá os princípios básicos desse paradigma de desenvolvimento e entenderá como essa abordagem difere da programação orientada a objetos ou imperativa.




Valores e Funções


Mais uma vez, considere esta função simples.


let add1 x = x + 1 

O que x significa aqui:


  1. Pegue algum valor do domínio (escopo).
  2. Use o nome " x " para fornecer esse valor para que ele possa ser acessado mais tarde.

Usar um nome para representar um valor é chamado de ligação. O nome " x " é "vinculado" ao valor de entrada.


Portanto, se você calcular uma função com um valor de entrada de, digamos, 5, acontecerá o seguinte: sempre que " x " estiver na definição original, o valor 5 será definido, semelhante à função "localizar e substituir" em um editor de texto.


 let add1 x = x + 1 add1 5 //  «x» with «5» // add1 5 = 5 + 1 = 6 //  6 

É importante entender que isso não é uma tarefa. " x " não é um "slot" e não é uma variável com um valor atribuído que pode ser alterado posteriormente. Esta é uma associação única do nome " x " com um determinado valor. Este valor é um dos números inteiros predefinidos e não pode ser alterado. I.e. uma vez ligado x não pode ser alterado . O rótulo, uma vez associado ao valor, é sempre associado a esse valor.


Este princípio é uma parte crítica do pensamento funcional: não existem "variáveis", apenas valores .


Funções como valores


Se você pensar um pouco mais, poderá ver que o nome “ add1 ” em si é apenas uma ligação a “uma função que aumenta a entrada em um”. A função em si é independente do nome anexado a ela.


Ao introduzir let add1 x = x + 1 , dizemos ao compilador F # "toda vez que você vê o nome" add1 ", substitua-o por uma função que adicione 1 à entrada". " add1 " é chamado de valor da função .


Para ver que a função não depende de seu nome, basta executar o seguinte código:


 let add1 x = x + 1 let plus1 = add1 add1 5 plus1 5 

Como você pode ver, " add " e " plus " são dois nomes vinculados à mesma função.


Você sempre pode identificar uma função de valor por sua assinatura, que possui o domain -> range formulário padrão domain -> range . A assinatura generalizada da função value:


 val functionName : domain -> range 

Valores simples


Imagine uma operação que não leva nada e sempre retorna 5.



Seria uma operação "constante".


Como isso pode ser descrito em F #? Queremos dizer ao compilador: “toda vez que você vir o nome c , substitua-o por 5”. Assim:


 let c = 5 

Ao calcular retornará:


 val c : int = 5 

Desta vez, não há seta correspondente, apenas um int. Do novo - um sinal de igual com o valor real deduzido após ele. O compilador F # sabe que essa ligação possui um valor conhecido, que sempre será retornado, ou seja, o número 5.


Em outras palavras, acabamos de definir uma constante ou, em termos de F #, um valor simples.
Você sempre pode distinguir um valor simples de uma função de valor, porque todos os valores simples têm uma assinatura semelhante:


 val aName: type = constant //  -   

Valores simples vs. valores de função | Significado simples vs. funções de valor


É importante entender que, em F #, diferentemente de outros idiomas como C #, há muito pouca diferença entre valores simples e funções de valor. Ambos os tipos são valores que podem ser associados a nomes (usando a palavra-chave let ), após os quais podem ser passados ​​para qualquer lugar. De fato, veremos em breve que a idéia de que funções são valores que podem ser passados ​​como entrada para outras funções é um dos aspectos principais do pensamento funcional.


Observe que há uma pequena diferença entre um valor simples e uma função de valor. Uma função sempre tem domínio e intervalo e deve ser "aplicada" ao argumento para retornar o resultado. Um valor simples não precisa ser calculado após a ligação. Usando o exemplo acima, se quisermos definir uma "função constante" que retorne 5, poderíamos usar:


 let c = fun()->5 // or let c() = 5 

A assinatura de tais funções tem a seguinte aparência:


 val c : unit -> int 

Não é assim:


 val c : int = 5 

Mais informações sobre a unit , sintaxe da função e funções anônimas serão fornecidas posteriormente.


"Valores" vs. "Objetos"


Em linguagens de programação funcionais, como F #, a maioria das coisas é chamada de "valores". Em linguagens orientadas a objetos, como C #, a maioria das coisas é chamada de "objetos". Qual é a diferença entre "meaning" e "object"?


O valor, como vimos acima, é um membro do domínio. O domínio de números inteiros, o domínio de cadeias, o domínio de funções que mapeiam números inteiros em cadeias e assim por diante. Em princípio, os valores são imutáveis ​​(não mutáveis). E os significados não têm o comportamento associado a eles.


Objetos na definição canônica são encapsulamento da estrutura de dados com comportamento associado (métodos). Em geral, os objetos devem ter um estado (ou seja, mutáveis) e todas as operações que alteram o estado interno devem ser fornecidas pelo próprio objeto (por meio de uma notação de "ponto").


No F #, mesmo os valores primitivos têm uma certa quantidade de comportamento de "objeto". Por exemplo, você pode obter o comprimento de uma string através de um ponto:


 «abc».Length 

Mas, em geral, evitaremos o termo "objeto" para valores padrão em F #, salvando-o para se referir a classes de pleno direito ou outros valores que fornecem métodos.


Nomeando valores


As convenções de nomenclatura padrão usadas para nomes de valores e funções são basicamente alfanuméricas + sublinhados. Mas há algumas adições:


  1. Você pode adicionar um apóstrofo em qualquer parte do nome, excluindo o primeiro caractere.

 A'b'c begin' //   

  1. O último caso é frequentemente usado como um rótulo para versões "diferentes" de um valor:

 let f = x let f' = derivative f let f'' = derivative f' 

ou para variáveis ​​com o mesmo nome com palavras-chave existentes


 let if' btf = if b then t else f 

Você também pode usar backticks duplos para qualquer string para torná-lo um identificador válido.


 ``this is a name`` ``123`` //  

Casos em que você pode precisar usar um truque de backtick duplo:


  • Quando você precisar usar um identificador que corresponda à palavra-chave.

 let ``begin`` = «begin» 

  • Quando você precisar usar linguagens naturais para regras de negócios, testes de unidade ou documentação executável no estilo BBD, como Cucumber.

 let ``is first time customer?`` = true let ``add gift to order`` = () if ``is first time customer?`` then ``add gift to order`` // - let [<Test>] ``When input is 2 then expect square is 4``= // code here // BDD clause let [<Given>] ``I have (.*) N products in my cart`` (n:int) = // code here 

Diferentemente do C #, a convenção de nomenclatura F # exige que as funções e os valores iniciem com uma letra minúscula e não maiúscula ( camelCase , não PascalCase ), a menos que sejam projetados para interagir com outras linguagens .NET. No entanto, tipos e módulos usam letras maiúsculas (no início).


Recursos Adicionais


Existem muitos tutoriais para F #, incluindo materiais para quem vem com experiência em C # ou Java. Os links a seguir podem ser úteis à medida que você avança no F #:



Várias outras maneiras de começar a aprender F # também são descritas.


Finalmente, a comunidade F # é muito amigável para iniciantes. Há um bate-papo muito ativo no Slack, suportado pela F # Software Foundation, com salas para iniciantes nas quais você pode participar livremente . É altamente recomendável que você faça isso!


Não se esqueça de visitar o site da comunidade de língua russa F # ! Se você tiver alguma dúvida sobre o aprendizado de um idioma, teremos prazer em discuti-los nas salas de bate-papo:



Sobre autores de tradução


Traduzido por @kleidemos
As mudanças de tradução e editoriais foram feitas pelos esforços da comunidade de desenvolvedores de F # de língua russa . Agradecemos também a @schvepsss e @shwars pela preparação deste artigo para publicação.

Source: https://habr.com/ru/post/pt420039/


All Articles