14 excelentes razones para usar F #

F # es un lenguaje de programación funcional primero fuertemente tipado que le permite resolver problemas complejos escribiendo código simple. Basado en ML y construido en .NET Framework, F # ofrece buena interoperabilidad, portabilidad y velocidad de tiempo de ejecución, así como las "Cinco C": concisión, conveniencia, corrección, simultaneidad e integridad.

F # inicialmente estaba disponible solo en Windows, como un proyecto de investigación de Microsoft, pero ahora es un lenguaje de primera clase en varias plataformas. Puede usar F # en Mac y Linux con soporte de herramientas en Xamarin Studio, MonoDevelop, Emacs y otros; en Windows con Visual Studio, Xamarin Studio y Emacs; y en dispositivos Android e iOS y en la Web usando HTML5. Además de la programación de propósito general, F # es aplicable al código de la GPU, big data, juegos y mucho más.

¿Por qué usar F #? Déjame darte 14 razones.

F # es interactivo

Una de las ventajas de F # es que tiene un REPL interactivo (lectura, evaluación, impresión, bucle) donde puede probar el código, como se muestra en la imagen de pantalla a continuación. En el sentido de las agujas del reloj, desde la parte superior izquierda, vemos ventanas interactivas de F # desde Visual Studio en Windows, desde TryFSharp ejecutándose en Chrome y desde Xamarin Studio ejecutándose en Mac OS X. El ;;le dice a F # Interactive que evalúe lo que ha escrito; en TryFSharp, el botón "ejecutar" envía la misma señal. El uso de un REPL para compilar y probar el código antes de que entre en un programa completo acelera el desarrollo y reduce los errores.

F # es para secuencias de comandos

F # se puede utilizar como lenguaje de scripting y también como lenguaje de programación. A continuación, vemos una muestra de Visual Studio en la que un script F # carga cuatro archivos de programa F # y abre dos bibliotecas .NET antes de ejecutar su propio código. La notación [|…|]utilizada aquí declara una matriz. La notación |>es una tubería hacia adelante, que pasa el resultado del lado izquierdo a la función del lado derecho. Las nuevas líneas aquí no son sintácticamente significativas. Simplemente hacen que el código sea más fácil de leer que tener expresiones de tubería completas en una sola línea.

F # es funcional

F # admite construcciones de programación funcional tales como tratar funciones como valores, usar funciones sin nombre en expresiones, composición de funciones para formar nuevas funciones, funciones currizadas y la definición implícita de funciones mediante la aplicación parcial de argumentos de función. En la captura de pantalla superior a continuación, definimos y usamos una addfunción. El cuerpo de la función está sangrado (como Python) y los tipos de argumentos se infieren como números enteros debido al +operador. En la captura de pantalla inferior, proporcionamos una anotación de tipo después del nombre del argumento usando dos puntos y un nombre de tipo, por lo que F # sabe que phrasees un stringtipo.

F # es conciso

El siguiente código es un algoritmo similar a Quicksort implementado en F # (por Scott Wlaschin). La recpalabra clave indica que la función es recursiva. La match..withsintaxis es una switchdeclaración sobre los esteroides, con |casos indicativos. El []indica una lista vacía. Los firstElemy otherElementsse crean automáticamente.

Tenga en cuenta que no se mencionan declaraciones de tipo en ninguna parte del código, lo que significa que la función puede ordenar listas que contengan cualquier tipo que admita operadores de comparación. La funpalabra clave es para definir una función lambda anónima.

dejar rec lista de ordenación rápida =

   lista de coincidencias con

   | [] -> // Si la lista está vacía

        [] // devuelve una lista vacía

   | firstElem :: otherElements -> // Si la lista no está vacía 

        let smallElements = // extraer los más pequeños

            otros elementos            

            |> List.filter (fun e -> e <firstElem)

            |> quicksort // y ordenarlos

        let largeElements = // extraer los grandes

            otros elementos

            |> List.filter (divertido e -> e> = firstElem)

            |> quicksort // y ordenarlos

        // Combina las 3 partes en una nueva lista y devuélvela

        List.concat [SmallElements; [firstElem]; LargeElements]

//prueba

printfn "% A" (ordenación rápida [1; 5; 23; 18; 9; 1; 3])

A modo de comparación, eche un vistazo a la implementación tradicional de C # a continuación.

clase pública QuickSortHelper

{

   Public static List QuickSort (valores de lista)

      donde T: IComparable

   {

      si (valores.Cuenta == 0)

      {

         return new List ();

      }

      // obtener el primer elemento

      T firstElement = valores [0];

      // obtener los elementos más pequeños y más grandes

      var SmallElements = new List ();

      var largeElements = new List ();

      for (int i = 1; i <valores.Cuento; i ++) // i comienza en 1

      {// ¡no 0!

         var elem = valores [i];

         si (elem.CompareTo (primerElemento) <0)

         {

            SmallElements.Add (elem);

         }

         más

         {

            LargeElements.Add (elem);

         }

      }

      // devuelve el resultado

      var result = new List ();

      result.AddRange (QuickSort (smallElements.ToList ()));

      resultado.Añadir (primerElemento);

      result.AddRange (QuickSort (largeElements.ToList ()));

      devolver resultado;

   }

}

Notará cuánto extra tiene el código C # en comparación con el código F #. 

F # es realmente conciso

Según Scott Wlaschin, la versión de ordenación rápida que se muestra a continuación (las cuatro líneas) tiene el aspecto conciso típico de F # escrito por un codificador funcional experimentado. Por supuesto, él sería el primero en señalar que no se ordena en su lugar. Me tomó varias lecturas comprender el código, pero valió la pena.

dejar rec quicksort2 = función

   | [] -> []                        

   | primero :: descanso ->

        dejar más pequeño, más grande = List.partition ((> =) primero) descansar

        List.concat [quicksort2 más pequeño; [primero]; quicksort2 más grande]

// código de prueba 

printfn "% A" (quicksort2 [1; 5; 23; 18; 9; 1; 3])

Brevemente, el primer caso devuelve una lista vacía si se pasa una, proporcionando un criterio de salida; el segundo caso divide la lista en el primer elemento y el resto, asignando la sublista comenzando con el valor más pequeño smalleray la otra sublista a larger. Dentro de la concatenación de las sublistas, la función ordena de forma recursiva las listas smallery larger.

F # reduce los errores mediante una escritura fuerte

A diferencia de JavaScript, Ruby y Python, F # se escribe fuertemente, no dinámicamente. A diferencia de C y C ++, que también están fuertemente tipados, pero requieren que se declaren todos los tipos, F # realiza la inferencia de tipos siempre que sea posible. Cuando la inferencia de tipos no es posible, pero es necesario conocer el tipo, el compilador de F # arrojará un error y le sugerirá que proporcione una anotación de tipo, como tuvimos que hacer en un ejemplo anterior para el (phrase:string)argumento de la toHackerTalkfunción. Detectar una falta de coincidencia de tipos en tiempo de compilación elimina toda una clase de errores en tiempo de ejecución a los que son propensos los lenguajes de escritura dinámica.

Por cierto, los letenlaces de F # son inmutables a menos que los declare específicamente mutable.

F # tiene un conjunto grande y bien elegido de objetos, incluidos List, String y Array

Como puede ver en IntelliSense a continuación, F # tiene ricos módulos List, String y Array basados ​​en .NET Framework. En este sentido, también es un lenguaje orientado a objetos, aunque es ante todo un lenguaje funcional. Tenga en cuenta que no importa si usa el nombre del módulo o un nombre de variable escrito; cuando agregue el punto, aparecerán las funciones miembro. Algunas personas argumentan que usar explícitamente el nombre del módulo es un mejor estilo para un lenguaje funcional que las variables con puntos, pero no creo completamente en ese argumento.

F # es útil para MapReduce

MapReduce es un proceso eficiente de dos pasos que se utiliza a menudo en big data y se admite explícitamente en Hadoop. En este ejemplo de F #, estamos mapeando y reduciendo una lista de enteros. Primero filtramos la lista a los números pares, luego duplicamos cada número y finalmente tomamos la suma de todos los elementos de la lista para sumar o reducir el resultado. List.mapes una poderosa función de orden superior; una función de orden superior es aquella que toma otra función como argumento. Además de listas y matrices, F # admite registros, secuencias, proveedores de tipos de datos y LINQ (consulta integrada en el lenguaje).

F # tiene registros

Los registros F # representan agregados simples de valores con nombre, opcionalmente con miembros. En el siguiente ejemplo, primero definimos un Booktipo de registro con cuatro valores nombrados y luego creamos un registro usando los mismos cuatro nombres. El compilador de F # infiere correctamente el Booktipo haciendo coincidir los nombres.

Los registros de F # pueden tener valores opcionales

Los registros no siempre tienen que incluir todos sus valores con nombre. Si le da un valor con nombre al optionatributo cuando define el tipo, entonces puede quedar fuera de un registro. Cuando establece un valor opcional, puede ser None, que termina como a null, o puede ir Someseguido del valor que desea establecer. Los campos de registro se diferencian de las clases en que se exponen automáticamente como propiedades. Las clases y estructuras en F # son clases y estructuras .NET, compatibles con C # y Visual Basic .NET, así que renunciaré a los ejemplos.

F # tiene secuencias

Una secuencia en F # es una serie lógica de elementos todos de un tipo. Las secuencias son particularmente útiles cuando tiene una colección de datos grande y ordenada, pero no necesariamente espera usar todos los elementos. Los elementos de secuencia individuales se calculan solo según sea necesario, por lo que una secuencia puede proporcionar un mejor rendimiento que una lista en situaciones en las que no se utilizan todos los elementos. El Seqmódulo proporciona soporte para manipulaciones que involucran secuencias. En la siguiente imagen, mostramos secuencias simples, secuencias con expresiones y secuencias con filtros.

F # admite proveedores de datos y LINQ

A continuación, usamos el editor TryFSharp para abrir un conjunto de datos meteorológicos de Freebase en línea y consultar al proveedor de datos sobre ciclones que hayan registrado los valores de viento más altos. La query { }sintaxis implementa LINQ para F #. El uso de esta DLL es específico de TryFSharp. En Visual Studio, debería open Microsoft.FSharp.Data.TypeProvidersutilizar el servicio de proveedor de datos adecuado.

El resultado:

 [Hurricane Andrew; Hurricane Hugo; 1900 Galveston hurricane;

   Tropical Storm Allison; Cyclone Tracy; Hurricane Iniki; Hurricane Ivan;

   1999 Odisha cyclone; Hurricane Katrina; Typhoon Talim; Hurricane Rita;

   Typhoon Herb; Hurricane Wilma; Typhoon Vera; 1962 Pacific typhoon season;

   Typhoon Ike; Typhoon Mireille; Typhoon Babe; Tropical Storm Arlene;

   Hurricane Irene; Typhoon Zeb; Typhoon Maemi; Typhoon Bess; Typhoon Chanchu;

   Typhoon Patsy; Typhoon Ewiniar; Hurricane Ioke; Typhoon Xangsane;…

F # puede analizar datos de Hadoop

En este ejemplo, usamos el editor TryFsharp para abrir una instancia de Hadoop Hive que contiene, entre otros conjuntos de datos, mediciones de características de flores de iris, junto con anotaciones de unidades de medida. En consecuencia, hemos habilitado el uso de anotaciones de unidades en las propiedades de HiveTypeProvider.

Este cálculo devuelve:

val avgPetalLength : float = 0.0374966443

F # hace coincidencia de patrones

La matchexpresión F # proporciona un control de ramificación que se basa en la comparación de una expresión con un conjunto de patrones. Las líneas 1-7 del ejemplo siguiente definen una isPalindromefunción recursiva . Las líneas 8-10 definen una función contenedora para la isPalindromeque la llama la primera vez que usa toda la cadena. Debido a que “aba” es un palíndromo, la thencláusula de la línea 9 se dispara y regresa Some s, y la matchdeclaración en la línea 11 genera “La cadena aba es palíndromo”. El _ patternde la línea 14 es el caso predeterminado.

La match..|instrucción en F # tiene muchos beneficios sobre la switch..caseinstrucción en C #, C ++ y Java, la más importante de las cuales es que causa menos errores.

F # admite flujos de trabajo asincrónicos

F # tiene acceso a todo .NET Framework, pero también tiene su propia sintaxis para flujos de trabajo asincrónicos. La async { expression }sintaxis define un cálculo sin bloqueo. La do!palabra clave realiza una operación asincrónica y espera el resultado. La let!palabra clave espera una operación asincrónica y asigna el resultado. Y use!espera una operación asincrónica, asigna el resultado y libera el recurso. Async.RunSynchronouslyejecuta una operación asincrónica y espera su resultado. Para agregar paralelismo, use la Async.Parallelfunción, que toma una lista de los Asyncobjetos, configura el código para que cada Asyncobjeto de tarea se ejecute en paralelo y devuelve un Asyncobjeto que representa el cálculo paralelo. Luego canalice ese resultado a Async.RunSynchronously. (El siguiente ejemplo es deF # por diversión y ganancias .)

Recursos de F #

Para obtener más información sobre F #, siga los vínculos siguientes.

  • Prueba F #
  • F # por diversión y ganancias
  • Referencia del lenguaje F #
  • Programación funcional del mundo real
  • Libros de F # en Amazon
  • Libro blanco de F # 3
  • Referencias adicionales