Introducción a la programación funcional en F#Introduction to Functional Programming in F#

Programación funcional es un estilo de programación que resalta el uso de funciones y datos inmutables.Functional programming is a style of programming that emphasizes the use of functions and immutable data. Programación funcional con tipo es cuando se combina la programación funcional con tipos estáticos, como con F#.Typed functional programming is when functional programming is combined with static types, such as with F#. En general, se destacan los siguientes conceptos de programación funcional:In general, the following concepts are emphasized in functional programming:

  • Funciones como las construcciones principales que usarFunctions as the primary constructs you use
  • Expresiones en lugar de instruccionesExpressions instead of statements
  • Valores inmutables sobre las variablesImmutable values over variables
  • Programación declarativa a través de la programación imperativaDeclarative programming over imperative programming

A lo largo de esta serie, exploraremos los conceptos y patrones de programación funcional mediante F#.Throughout this series, you'll explore concepts and patterns in functional programming using F#. En el camino, obtendrá información sobre algunos F# demasiado.Along the way, you'll learn some F# too.

TerminologíaTerminology

Incluye un vocabulario que finalmente deberá aprender programación funcional, al igual que otros paradigmas de programación.Functional programming, like other programming paradigms, comes with a vocabulary that you will eventually need to learn. Estos son algunos términos comunes que verá todo el tiempo:Here are some common terms you'll see all of the time:

  • Función -una función es una construcción que generará un resultado cuando se especifica una entrada.Function - A function is a construct that will produce an output when given an input. Más formalmente, lo asigna establece un elemento de uno a otro conjunto.More formally, it maps an item from one set to another set. Este formalismo se levanta en lo concreto en muchos sentidos, especialmente cuando se usa funciones que operan en colecciones de datos.This formalism is lifted into the concrete in many ways, especially when using functions that operate on collections of data. Es un concepto más básico (e importante) en la programación funcional.It is the most basic (and important) concept in functional programming.
  • Expresión : una expresión es una construcción de código que genera un valor.Expression - An expression is a construct in code that produces a value. En F#, este valor debe ser enlazada o explícitamente se omiten.In F#, this value must be bound or explicitly ignored. Una expresión se puede reemplazar de forma trivial mediante una llamada de función.An expression can be trivially replaced by a function call.
  • Pureza -pureza es una propiedad de una función de modo que su valor devuelto siempre es el mismo para los mismos argumentos, y que su evaluación tiene efectos secundarios.Purity - Purity is a property of a function such that its return value is always the same for the same arguments, and that its evaluation has no side effects. Una función pura depende por completo sus argumentos.A pure function depends entirely on its arguments.
  • Transparencia referencial -transparencia referencial es una propiedad de las expresiones de modo que puedan reemplazarse con sus resultados sin afectar al comportamiento de un programa.Referential Transparency - Referential Transparency is a property of expressions such that they can be replaced with their output without affecting a program's behavior.
  • La inmutabilidad -significa de inmutabilidad que no puede ser un valor cambiado en contexto.Immutability - Immutability means that a value cannot be changed in-place. Se trata a diferencia de las variables, que pueden cambiar en su lugar.This is in contrast with variables, which can change in place.

EjemplosExamples

Los ejemplos siguientes muestran estos conceptos básicos.The following examples demonstrate these core concepts.

FuncionesFunctions

Una construcción más comunes y fundamental en la programación funcional es la función.The most common and fundamental construct in functional programming is the function. Esta es una función sencilla que suma 1 a un entero:Here's a simple function that adds 1 to an integer:

let addOne x = x + 1

La firma de su tipo es como sigue:Its type signature is as follows:

val addOne: x:int -> int

La firma se puede leer como, "addOne acepta un int denominado x y generará una int".The signature can be read as, "addOne accepts an int named x and will produce an int". Más formalmente, addOne es asignación un valor del conjunto de enteros para el conjunto de enteros.More formally, addOne is mapping a value from the set of integers to the set of integers. El -> token significa que esta asignación.The -> token signifies this mapping. En F#, normalmente puede mirar la firma de función para hacerse una idea de lo que hace.In F#, you can usually look at the function signature to get a sense for what it does.

Por lo tanto, ¿por qué la firma es importante?So, why is the signature important? En la programación funcional con tipo, la implementación de una función suele ser más importante que la firma del tipo real.In typed functional programming, the implementation of a function is often less important than the actual type signature! El hecho de que addOne agrega el valor 1 en un entero es interesante en tiempo de ejecución, pero cuando se construye un programa, el hecho de que acepte y devuelva un int es lo que le informa de cómo lo utilizará esta función.The fact that addOne adds the value 1 to an integer is interesting at runtime, but when you are constructing a program, the fact that it accepts and returns an int is what informs how you will actually use this function. Además, una vez que use esta función correctamente (con respecto a su signatura de tipo), diagnosticar problemas puede realizarse solo dentro del cuerpo de la addOne función.Furthermore, once you use this function correctly (with respect to its type signature), diagnosing any problems can be done only within the body of the addOne function. Este es el impulso que hay detrás de la programación funcional con tipo.This is the impetus behind typed functional programming.

ExpresionesExpressions

Las expresiones son construcciones que se evalúan como un valor.Expressions are constructs that evaluate to a value. A diferencia de las instrucciones, que realizan una acción, se pueden considerar las expresiones de llevar a cabo una acción que devuelve un valor.In contrast to statements, which perform an action, expressions can be thought of performing an action that gives back a value. Las expresiones se usan casi siempre en favor de las instrucciones en la programación funcional.Expressions are almost always used in favor of statements in functional programming.

Considere la función anterior, addOne.Consider the previous function, addOne. El cuerpo de addOne es una expresión:The body of addOne is an expression:

// 'x + 1' is an expression!
let addOne x = x + 1

Es el resultado de esta expresión que define el tipo de resultado de la addOne función.It is the result of this expression that defines the result type of the addOne function. Por ejemplo, se pudo cambiar la expresión que constituye esta función para que sea un tipo diferente, como un string:For example, the expression that makes up this function could be changed to be a different type, such as a string:

let addOne x = x.ToString() + "1"

La firma de la función ahora es:The signature of the function is now:

val addOne: x:'a -> string

Desde cualquier tipo de F# puede tener ToString() llamado en ella, el tipo de x se ha realizado genérico (llamado generalización automática), y el tipo resultante es un string.Since any type in F# can have ToString() called on it, the type of x has been made generic (called Automatic Generalization), and the resultant type is a string.

Las expresiones no son simplemente los cuerpos de funciones.Expressions are not just the bodies of functions. Puede hacer que las expresiones que producen un valor que se usa en otro lugar.You can have expressions that produce a value you use elsewhere. Es un común if:A common one is if:

// Checks if 'x' is odd by using the mod operator
let isOdd x = x % 2 <> 0

let addOneIfOdd input =
    let result =
        if isOdd input then
            input + 1
        else
            input

    result

El if expresión genera un valor denominado result.The if expression produces a value called result. Tenga en cuenta que puede omitir result por completo, que hace el if el cuerpo de la expresión de la addOneIfOdd función.Note that you could omit result entirely, making the if expression the body of the addOneIfOdd function. La clave que debe recordar acerca de las expresiones es que genera un valor.The key thing to remember about expressions is that they produce a value.

Hay un tipo especial, unit, que se utiliza cuando hay que devolver nada.There is a special type, unit, that is used when there is nothing to return. Por ejemplo, considere la posibilidad de esta función simple:For example, consider this simple function:

let printString (str: string) =
    printfn "String is: %s" str

La firma tiene este aspecto:The signature looks like this:

val printString: str:string -> unit

El unit tipo indica que no hay ningún valor real que se devuelve.The unit type indicates that there is no actual value being returned. Esto es útil cuando tiene una rutina que debe "funcione" a pesar de no tener ningún valor para devolver como resultado de ese trabajo.This is useful when you have a routine that must "do work" despite having no value to return as a result of that work.

Esto es en contraste con la programación imperativa, donde el equivalente if construcción es una instrucción y generar los valores se suele hacer con las variables de mutación.This is in sharp contrast to imperative programming, where the equivalent if construct is a statement, and producing values is often done with mutating variables. Por ejemplo, en C#, se podría escribir el código similar al siguiente:For example, in C#, the code might be written like this:

bool IsOdd(int x) => x % 2 != 0;

int AddOneIfOdd(int input)
{
    var result = input;

    if (IsOdd(input))
    {
        result = input + 1;
    }

    return result;
}

Merece la pena mencionar que C# y otros lenguajes de estilo de C admiten la expresión ternaria, lo que permite la programación condicional basada en expresión.It's worth noting that C# and other C-style languages do support the ternary expression, which allows for expression-based conditional programming.

En la programación funcional, es poco frecuente mutar valores con instrucciones.In functional programming, it is rare to mutate values with statements. Aunque algunos lenguajes funcionales son compatibles con las instrucciones y mutación, no es habitual usar estos conceptos en la programación funcional.Although some functional languages support statements and mutation, it is not common to use these concepts in functional programming.

Funciones purasPure functions

Como se mencionó anteriormente, puras funciones son funciones:As previously mentioned, pure functions are functions that:

  • Evalúe siempre el mismo valor para la misma entrada.Always evaluate to the same value for the same input.
  • No tienen efectos secundarios.Have no side effects.

Resulta útil pensar en las funciones matemáticas en este contexto.It is helpful to think of mathematical functions in this context. En matemáticas, las funciones sólo dependen de sus argumentos y no tiene efectos secundarios.In mathematics, functions depend only on their arguments and do not have any side effects. En la función matemática f(x) = x + 1, el valor de f(x) solo depende del valor de x.In the mathematical function f(x) = x + 1, the value of f(x) depends only on the value of x. Las funciones puras en la programación funcional son la misma manera.Pure functions in functional programming are the same way.

Al escribir una función pura, la función debe depender únicamente de sus argumentos y no realiza ninguna acción que da como resultado un efecto secundario.When writing a pure function, the function must depend only on its arguments and not perform any action that results in a side effect.

Este es un ejemplo de una función no pura porque depende de estado mutable global:Here is an example of a non-pure function because it depends on global, mutable state:

let mutable value = 1

let addOneToValue x = x + value

El addOneToValue función es claramente impuras, porque value podría cambiarse en cualquier momento para tener un valor distinto de 1.The addOneToValue function is clearly impure, because value could be changed at any time to have a different value than 1. Este patrón de según un valor global es que deben evitarse en la programación funcional.This pattern of depending on a global value is to be avoided in functional programming.

Este es otro ejemplo de una función no pura, ya que realiza un efecto secundario:Here is another example of a non-pure function, because it performs a side effect:

let addOneToValue x = 
    printfn "x is %d" x
    x + 1

Aunque esta función no depende de un valor global, escribe el valor de x a la salida del programa.Although this function does not depend on a global value, it writes the value of x to the output of the program. Aunque no hay ningún problema inherente al hacer esto, ¿significa que la función no es pura.Although there is nothing inherently wrong with doing this, it does mean that the function is not pure. Si otra parte del programa depende de algo externo para el programa, como el búfer de salida, a continuación, llamar a esta función puede afectar a otra parte del programa.If another part of your program depends on something external to the program, such as the output buffer, then calling this function can affect that other part of your program.

Quitar el printfn instrucción hace que la función pura:Removing the printfn statement makes the function pure:

let addOneToValue x = x + 1

Aunque esta función no es intrínsecamente mejor que la versión anterior con el printfn instrucción, garantizar que todo lo que hace esta función es devolver un valor.Although this function is not inherently better than the previous version with the printfn statement, it does guarantee that all this function does is return a value. Llamar a esta función en cualquier número de veces que produce el mismo resultado: solo genera un valor.Calling this function any number of times produces the same result: it just produces a value. La capacidad de predicción dado por la pureza es algo que muchos programadores funcionales se esfuerzan por lograr.The predictability given by purity is something many functional programmers strive for.

InmutabilidadImmutability

Por último, uno de los conceptos más fundamentales de la programación funcional con tipo es la inmutabilidad.Finally, one of the most fundamental concepts of typed functional programming is immutability. En F#, todos los valores son inmutables de manera predeterminada.In F#, all values are immutable by default. Esto significa que no pueden ser transformarlos in situ a menos que marque explícitamente como mutables.That means they cannot be mutated in-place unless you explicitly mark them as mutable.

En la práctica, trabajar con valores inmutables significa que cambiar su enfoque a la programación de "Necesito cambiar algo" a "necesito generar un nuevo valor".In practice, working with immutable values means that you change your approach to programming from, "I need to change something", to "I need to produce a new value".

Por ejemplo, agregando 1 a un valor significa que generar un nuevo valor, no una mutación existente:For example, adding 1 to a value means producing a new value, not mutating the existing one:

let value = 1
let secondValue = value + 1

En F#, el código siguiente hace no mutar la value función; en su lugar, realiza una comprobación de igualdad:In F#, the following code does not mutate the value function; instead, it performs an equality check:

let value = 1
value = value + 1 // Produces a 'bool' value!

Algunos lenguajes de programación funcionales no admiten mutación en absoluto.Some functional programming languages do not support mutation at all. En F#, que es compatible, pero no es el comportamiento predeterminado para los valores.In F#, it is supported, but it is not the default behavior for values.

Este concepto se extiende más allá de las estructuras de datos.This concept extends even further to data structures. En la programación funcional, estructuras de datos inmutables como conjuntos (y muchos más) tienen una implementación diferente que inicialmente podría esperan.In functional programming, immutable data structures such as sets (and many more) have a different implementation than you might initially expect. Conceptualmente, algo así agregando un elemento a un conjunto no cambia el conjunto, genera un nuevo establecido con el valor agregado.Conceptually, something like adding an item to a set does not change the set, it produces a new set with the added value. En segundo plano, a menudo esto se logra mediante una estructura de datos diferentes que se permite para el seguimiento de forma eficaz un valor para que la representación apropiada de los datos puede tener como resultado.Under the covers, this is often accomplished by a different data structure that allows for efficiently tracking a value so that the appropriate representation of the data can be given as a result.

Este estilo de trabajar con los valores y las estructuras de datos es fundamental, tal como nos vemos obligados a tratar cualquier operación que modifique algo como si crea una nueva versión de eso.This style of working with values and data structures is critical, as it forces you to treat any operation that modifies something as if it creates a new version of that thing. Esto permite cosas como comprobar su igualdad y comparación para que sea coherente en los programas.This allows for things like equality and comparability to be consistent in your programs.

Pasos siguientesNext steps

La siguiente sección tratará exhaustivamente las funciones, explorar maneras diferentes, puede usar en la programación funcional.The next section will thoroughly cover functions, exploring different ways you can use them in functional programming.

Funciones de primera clase explora funciones profundamente, que muestra cómo puede usarlos en distintos contextos.First-class functions explores functions deeply, showing how you can use them in various contexts.

Información adicionalFurther reading

El funcionalmente pensando serie es otro excelente recurso para aprender sobre la programación funcional con F#.The Thinking Functionally series is another great resource to learn about functional programming with F#. Abarca conceptos básicos de la programación funcional de forma pragmática y fácil de leer, con F# características para ilustrar los conceptos.It covers fundamentals of functional programming in a pragmatic and easy-to-read way, using F# features to illustrate the concepts.