Refatorar em funções puras (LINQ to XML)
Um aspecto importante de transformações e puras é aprender como o código do refatorar usando funções puras.
Observação
A nomenclatura comuns em programação funcional é que você refatora programa usando funções puras. No Visual Basic e C++, isso alinha com o uso das funções em linguagens respectivos. No entanto, em C#, as funções são chamadas métodos. Para fins desta discussão, uma função pura é implementada como um método em C#.
Conforme observado anteriormente nesta seção, uma função pura tem duas características úteis:
- Não tem efeito colateral. A função não altera quaisquer variáveis ou os dados de qualquer tipo fora da função.
- É consistente. Dado o mesmo conjunto de dados de entrada, sempre retornará o mesmo valor de saída.
Uma maneira de fazer a transição para programação funcional é o código existente do refatorar para eliminar efeitos colaterais desnecessários e dependências externas. Dessa maneira, você pode criar versões puras de função do código existente.
Este artigo descreve o que é uma função pura e o que não é. O tutorial Tutorial: Manipular conteúdo em um documento WordprocessingML mostra como manipular um documento WordprocessingML e inclui dois exemplos de como refatorar usando uma função pura.
Os seguintes exemplos contrastam duas funções não puras e uma função pura.
Exemplo: implementar uma função não pura que altera um membro de classe estática
No seguinte código, a função HyphenatedConcat
não é uma função pura, pois ela modifica o membro da classe estática aMember
:
public class Program
{
private static string aMember = "StringOne";
public static void HyphenatedConcat(string appendStr)
{
aMember += '-' + appendStr;
}
public static void Main()
{
HyphenatedConcat("StringTwo");
Console.WriteLine(aMember);
}
}
Module Module1
Dim aMember As String = "StringOne"
Public Sub HyphenatedConcat(ByVal appendStr As String)
aMember = aMember & "-" & appendStr
End Sub
Sub Main()
HyphenatedConcat("StringTwo")
Console.WriteLine(aMember)
End Sub
End Module
Esse exemplo gera a saída a seguir:
StringOne-StringTwo
Observe que é irrelevante se os dados modificados têm acesso a public
ou private
ou são um membro de static
, de shared
ou um membro de instância. Uma função pura não altera quaisquer dados fora da função.
Exemplo: implementar uma função não pura que altera um parâmetro
Além disso, a versão a seguir dessa mesma função não é pura porque modifica o conteúdo do seu parâmetro, sb
.
public class Program
{
public static void HyphenatedConcat(StringBuilder sb, String appendStr)
{
sb.Append('-' + appendStr);
}
public static void Main()
{
StringBuilder sb1 = new StringBuilder("StringOne");
HyphenatedConcat(sb1, "StringTwo");
Console.WriteLine(sb1);
}
}
Module Module1
Public Sub HyphenatedConcat(ByVal sb As StringBuilder, ByVal appendStr As String)
sb.Append("-" & appendStr)
End Sub
Sub Main()
Dim sb1 As StringBuilder = New StringBuilder("StringOne")
HyphenatedConcat(sb1, "StringTwo")
Console.WriteLine(sb1)
End Sub
End Module
Esta versão do programa gerenciar as mesmas saída que a primeira versão, porque a função de HyphenatedConcat
alterou o valor (estado) do primeiro parâmetro chamar a função de membro de Append . Observe que essa mudança ocorre independentemente do fato de que HyphenatedConcat
usa passar o parâmetro de atendimento-por- valor.
Importante
Para tipos de referência, se você passa um parâmetro por valor, ele resulta em uma cópia de referência a um objeto que está sendo passado. Esta cópia ainda está associada com os mesmos dados de instância que a referência original (até que a variável de referência é atribuído a um novo objeto). A chamada por referência não necessariamente é obrigatória para uma função modificar um parâmetro.
Exemplo: implementar uma função pura
Esta próxima versão do programa mostra como implementar a função HyphenatedConcat
como uma função pura.
class Program
{
public static string HyphenatedConcat(string s, string appendStr)
{
return (s + '-' + appendStr);
}
public static void Main(string[] args)
{
string s1 = "StringOne";
string s2 = HyphenatedConcat(s1, "StringTwo");
Console.WriteLine(s2);
}
}
Module Module1
Public Function HyphenatedConcat(ByVal s As String, ByVal appendStr As String) As String
Return (s & "-" & appendStr)
End Function
Sub Main()
Dim s1 As String = "StringOne"
Dim s2 As String = HyphenatedConcat(s1, "StringTwo")
Console.WriteLine(s2)
End Sub
End Module
Além disso, esta versão gerencia a mesma linha de saída: StringOne-StringTwo
. Observe que para manter o valor concatenado, ele é armazenado em s2
variável intermediária.
Uma abordagem que pode ser muito útil é escrever as funções que são localmente impuros (isto é, declare e alteram variáveis locais) mas é global pura. Tais funções têm muitas das características desejáveis de composability, mas impedem alguns de linguagem e mais complicados de programação, como ter que usar a recursão quando um loop simples realizaria a mesma coisa.
Operadores de consulta padrão
Uma característica importante dos operadores de consulta padrão é que são implementados como funções puras.
Para mais informações, confira Visão geral de operadores de consulta padrão (C#) e Visão geral de operadores de consulta padrão (Visual Basic).