F# es un lenguaje fuertemente tipado que utiliza inferencia de tipos. Como resultado, los tipos no necesitan estar
declarados explícitamente por el programador; estos serán deducidos por el compilador durante el proceso de compilación. Sin
embargo, F# también permite la declaración explícita de tipos de datos. Por ser un lenguaje .NET, F# soporta los objetos y tipos de .NET; F# permite al programador programar de una manera que se asemeja más a como pensamos. Por ejemplo: en la cafetería para pedir un café, nosotros generalmente no le decimos al mesero exactamente los pasos para hacer el café, solo pedimos un café con ciertas características. De tal forma que tenemos menos espacio para cometer errores, porque simplemente escribimos menos código. También facilita enormemente la creación de código asincrónico y paralelo, cosa que en otros lenguajes de .NET nos llevaría mucho más tiempo.
General
Programación Funcional
F# es un lenguaje de programación primeramente funcional, fuertemente tipado, que usa la inferencia de tipos. Los tipos no
necesitan ser explícitamente declarados por el programador; serán deducidos en proceso de compilación. F# también permite
notaciones explícitas de tipos y requiere de esto en algunas situaciones. F# es un lenguaje de expresiones basadas en evaluación impaciente. Las funciones y expresiones que no retornan ningún valor tienen como tipo de retorno unit. F# usa la palabra clave let para enlazar valores a nombres. Por ejemplo:
letx=3+4
enlaza el valor 7 al nombre x.
Nuevos tipos son definidos usando la palabra clave type. Para una programación funcional, F# provee los tipos
tuple, record, discriminated union, list y option. Una tupla representa una colección de
n valores. El valor n es llamado la aridad de la tupla. Una 3-tuple podría ser representado como (A, B, C), donde A, B y C son valores con posiblemente diferente tipos. Una tupla puede ser usada solamente para almacenar
valores cuando el número de valores es conocido en tiempo de diseño y permanece constante durante la ejecución.
Un record es un tipo donde los datos son nombrados, por ejemplo: { Name:string; Age:int }. Los récords
pueden ser creados como { Name="AB"; Age=42 }. La palabra clave with es usada para crear una copia
de un récord, por ejemplo: { r with Name="CD" }, el cual crea un nuevo récord copiando r y
cambiando el valor del campo Name (asumiendo que el récord creado en el ejemplo anterior fue nombrado
r).
Los valores de la unión pueden corresponder a cualquiera de los dos casos de unión. Los tipos de los valores de cada caso de
unión es incluido en la definición de cada caso. El tipo list es una lista enlazada inmutable representada usando la notación head::tail (:: el operador cons) o de forma de encabezado corto [item1; item2; item3]. Una lista vacía se denota como []. El tipo option es un tipo de unión discriminada con elección Some(x) o None. Los tipos de F# pueden ser genéricos, implementado como tipos genéricos de .NET.
F# soporta funciones lambda y clausuras. Todas las funciones en F# son
inmutables. Las funciones pueden ser curried. Las funciones pueden ser pasadas como argumento a otras
funciones. Como otros lenguajes de programación funcional, F# permite la composición de funciones
usando el operador >>.
F# provee expresiones de secuencia[3] que define una secuencia seq { ... }, lista [ ...
] o array [| ... |] a través de código que genera valores. Por ejemplo:
seq{forbin0..25doifb<15thenyieldb*b}
forma una secuencia de los cuadrados de los números de 0 a 14 filtrando afuera por los números que están en un rango de 0 a
25. Las secuencias son generadas a medida que va haciendo falta (i.e. are evaluación lazy), mientras que
las listas y arrays son evaluadas impacientemente. F# usa pattern matching para enlazar valores a nombres. Pattern matching es también usado cuando se está accediendo a uniones discriminadas. F# también soporta Active Patterns como un pattern matching extendido.[4] Este es usado, por ejemplo, cuando existen múltiples formas de matchear con un tipo. F# soporta una sintaxis general para la definición de composiciones llamado computation expressions. Secuencias de expresiones, computaciones asíncronas y consultas son clases particulares de computation expressions. "Computation expressions" son una implementación de monad pattern.[3]
En los patterns para programar con objetos se incluye:
type tests (e.g. :? string as s)
active patterns, el cual puede ser definido sobre tipos de objetos.[4]
Las definiciones de objetos en F# pueden ser clases, estructuras (struct), interfaz, enum o delegados, correspondiendo a las
formas de definición encontradas en C#. Por ejemplo, aquí se muestra una clase con un
constructor tomando un nombre y una edad, y declarando dos propiedades.
/// Una simple definición de tipo de objetotypePerson(name:string,age:int)=memberx.Name=namememberx.Age=age
Programación Asíncrona
F# soporta programación asíncrona a través de asynchronous workflows.[5] "Asynchronous workflow" es definido
como una secuencia de comandos dentro de un async{ ... }, por ejemplo:
El let! permite que el resto del bloque async pueda ser definido como un delegado y pasado como Callback (informática) de una operación asíncrona. Esto soluciona el problema de la [[inversion of
control|inversión de control]].[5] El bloque async es invocado usando la función Async.RunSynchronously. Múltiples bloques async son ejecutados en paralelo usando la función
Async.Parallel que toma una lista de objetos async (en el ejemplo, asynctask es un
objeto async) y crea otro objeto async para correr las tareas en las listas en paralelo. Luego, el objeto resultante es
invocado usando Async.RunSynchronously.[5]
Programación en Paralelo
La programación en paralelo es soportada parcialmente a través de Async.Parallel, Async.Start y
otras operaciones que corren bloques asíncronos en paralelo.
Meta-programación
F# permite algunas formas de sintaxis personalizadas con el fin de darle soporte a un incrustamiento
personalizado, particularmente a través de "computation expressions".
F# incluye un plugin para meta-programación en tiempo de ejecución llamado quotations.[6] Una expresión quotation evalúa una representación de sintaxis abstracta de expresiones de F#. Una definición etiquetada con el atributo [<ReflectedDefinition>] puede también ser accedida de la forma quotation. Las F# quotations son usadas
para varios propósitos incluyendo compilar código F# a JavaScript y GPU.
Information Rich
F# 3.0 introdujo una forma de meta-programación en tiempo de compilación a través de una generación de tipos estáticamente
extensibles llamados F# type providers.[7] F# type providers permite al compilador de F# y herramientas ser extendidas con componentes que proporcionan información de tipo al compilador. F# type providers ha sido usado para dar acceso a tipos fuertemente tipados para conectar el origen de la información en una manera escalable.[8]
En F# 3.0 el F# quotation y las computation expression son combinadas para implementar consultas LINQ.[9] Por ejemplo:
// Usa el OData type provider para crear tipos que puedan ser usados para acceder a Northwind database.openMicrosoft.FSharp.Data.TypeProviderstypeNorthwind=ODataService<"http://services.odata.org/Northwind/Northwind.svc">letdb=Northwind.GetDataContext()// A query expression.letquery1=query{forcustomerindb.Customersdoselectcustomer}
La combinación de type providers, consultas y programación funcional fuertemente tipado es conocido como information rich
programming.[10]
Agente
F# soporta una variante del modelo de programación Actor a través de la implementación en memoria de agentes
asíncronos. Por ejemplo, el siguiente código define un agente y envía 2 mensajes:
F# puede ser desarrollado con cualquier editor de texto. Hay soportes específicos para el en varios editores, por ejemplo Emacs.
La herramienta Visual F# de Microsoft incluye completa integración en el IDE Visual Studio.
Con el servicio del lenguaje instalado, Visual Studio puede ser usado para crear proyectos de F# y el Visual Studio debugger
usado para depurar código F#. Además las herramientas de Visual F# vienen con una consola interactiva que puede ser usada
para ejecutar código F# como está siendo escrito.
WebSharper es una plataforma para la utilización de JavaScript and HTML5.
MonoDevelop es un entorno de desarrollo integrado para Linux, Mac y Windows incluyendo soporte para una consola interactiva.
SharpDevelop soporta F# desde la versión 3.0.
LINQPad soporta F# desde la versión 2.X.
F# es usado en conjunto con ASP.NET, knockoutJS y otros frameworks del lado del servidor y del lado del cliente.[11]
F# es una parte central del framework WebSharper donde el código F# es ejecutado como un código .NET en el servidor y
como código JavaScript en el lado cliente.
Scripting
F# es sobre todo usado como un lenguaje de scripting, principalmente para escritorio.[12]
Comunidad Código Abierto
La comunidad de código abierto de F# incluye la F# Software Foundation y la F# Open Source Group at GitHub.
Ejemplos
Un corto y pequeño ejemplo:
// Esto es un comentario para el programa de ejemplo Hello World.printfn"Hello World!"
Una clase persona con un constructor que espera name, age y dos propiedades.
/// Este es el comentario para la documentacion de la definicion de un tipotypePerson(name:string,age:int)=memberx.Name=namememberx.Age=age
Un simple ejemplo que es sobre todo usado para demostrar la sintaxis de un lenguaje funcional:
/// Este es el comentario para la documentación de una funciónletrecfactorialn=matchnwith|0->1|_->n*factorial(n-1)
Ejemplos de iteraciones:
/// Iteración usando un ciclo 'for'letprintListlst=forxinlstdoprintfn"%d"x/// Iteración usando una función de alto nivel letprintList2lst=List.iter(printfn"%d")lst/// Iteración usando una función recursiva y pattern matchingletrecprintList3lst=matchlstwith|[]->()|h::t->printfn"%d"hprintList3t
Ejemplos de Fibonacci:
/// Numero n de fibonacciletrecfibn=matchnwith|0|1->n|_->fib(n-1)+fib(n-2)/// Otra aproximación, una secuencia lazy infinita de fibonacci letfibSeq=Seq.unfold(fun(a,b)->Some(a+b,(b,a+b)))(1,1)// Imprime los números de fibonacci pares [1..10]|>List.mapfib|>List.filter(funn->(n%2)=0)|>printList// Algunas cosas usando listas[foriin1..10doletr=fibiifr%2=0thenyieldr]|>printList
Un ejemplo con Windows Forms:
// Abre la librería Windows Forms openSystem.Windows.Forms// Crea una ventana y setea algunas propiedades letform=newForm(Visible=true,TopMost=true,Text="Welcome to F#")// Crea una etiqueta para mostrar algún texto en el formulario letlabel=letx=3+(4*5)newLabel(Text=sprintf"x = %d"x)//Añade la etiqueta al formularioform.Controls.Add(label)// Finalmente, corre el formulario [<System.STAThread>]Application.Run(form)
Ejemplo de programación paralela asíncrona:
/// Detectando números primosletisPrime(n:int)=letbound=int(sqrt(floatn))seq{2..bound}|>Seq.forall(funx->n%x<>0)// Usando async workflows letprimeAsyncn=async{return(n,isPrimen)}/// Retornando primos entre m y n usando hilosletprimesmn=seq{m..n}|>Seq.mapprimeAsync|>Async.Parallel|>Async.RunSynchronously|>Array.filtersnd|>Array.mapfst// Corriendo una prueba primes10000001002000|>Array.iter(printfn"%d")