¿En qué áreas podría ser más apropiado el uso de F # que C #? [cerrado]

210

En los últimos años, F # se ha convertido en uno de los lenguajes totalmente compatibles de Microsoft empleando muchas ideas incubadas en OCaml, ML y Haskell.

En los últimos años, C # ha ampliado sus funciones de propósito general mediante la introducción de funciones de lenguaje cada vez más funcionales: LINQ (comprensión de listas), Lambdas, Cierres, Delegados anónimos y más ...

Dada la adopción de C # de estas características funcionales y la taxonomía de F # como un lenguaje funcional impuro (le permite a USTED acceder a bibliotecas de marcos o cambiar el estado compartido cuando se llama a una función si lo desea), existe una fuerte similitud entre los dos lenguajes, aunque cada uno tiene su propio polar enfrente de énfasis primario.

Estoy interesado en cualquier modelo exitoso que emplee estos dos idiomas en sus programas políglotas de producción y también en las áreas dentro del software de producción (aplicaciones web, aplicaciones de cliente, aplicaciones de servidor) que haya escrito en F # durante el año pasado o para las que previamente tendría escrito en C #.

Peter McG
fuente

Respuestas:

258

He escrito una solicitud para equilibrar el cronograma nacional de generación de energía para una cartera de estaciones de energía a una posición comercial para una compañía de energía. Los componentes del cliente y el servidor estaban en C # pero el motor de cálculo estaba escrito en F #.

El uso de F # para abordar la complejidad en el corazón de esta aplicación demuestra claramente un punto óptimo para el lenguaje dentro del software empresarial, es decir, el análisis algorítmicamente complejo de grandes conjuntos de datos. Mi experiencia ha sido muy positiva. En particular:

Unidades de medida La industria en la que trabajo está llena de unidades. Las ecuaciones que implementé (a menudo de naturaleza geométrica) trataron con unidades de tiempo, potencia y energía. Hacer que el sistema de tipos verifique la exactitud de las unidades de las entradas y salidas de las funciones es un gran ahorro de tiempo, tanto en términos de prueba como de lectura / comprensión del código. Erradica toda una clase de errores a los que los sistemas anteriores eran propensos.

Programación exploratoria Trabajar con archivos de script y REPL (F # Interactive) me permitió explorar el espacio de la solución de manera más efectiva antes de comprometerme con una implementación que el ciclo tradicional de edición / compilación / ejecución / prueba. Es una forma muy natural para un programador desarrollar su comprensión del problema y las tensiones de diseño en juego.

Es un placer probar el código de prueba de unidad escrito con funciones de efectos no secundarios y estructuras de datos inmutables. No hay interacciones complejas dependientes del tiempo para arruinar las cosas o grandes conjuntos de dependencias para burlarse.

Interoperación Definí la interfaz para el motor de cálculo en C # e implementé el cálculo en F #. El motor de cálculo podría inyectarse en cualquier módulo C # que necesitara usarlo sin ninguna preocupación sobre la interoperabilidad. Sin costura. El programador de C # nunca necesita saberlo.

Reducción de código Gran parte de los datos introducidos en el motor de cálculo eran en forma de vectores y matrices. Las funciones de orden superior se comen en el desayuno con un mínimo de alboroto y un código mínimo. Hermoso.

Falta de errores La programación funcional puede parecer extraña. Puedo estar trabajando en un algoritmo, tratando de que el código pase el verificador de tipos, pero una vez que el verificador de tipos está satisfecho, funciona. Es casi binario, no compilará o es correcto. Los errores de casos extraños se minimizan, la recursividad y las funciones de orden superior eliminan una gran cantidad de código de contabilidad que introduce errores de casos extremos.

Paralelismo La pureza funcional de la implementación resultante lo hace maduro para explotar el paralelismo inherente en el procesamiento de vectores de datos. Tal vez aquí es donde iré ahora que .NET 4 está fuera.

primos simon
fuente
18
+1 para explicar por qué F # es muy adecuado para motores de cálculo numérico. Otro +1 (virtual) para mencionar unidades de medida. Esa parte del lenguaje merece ser mencionada con más frecuencia.
cfern
55
Gran respuesta, relevante, contemporánea y describe la idoneidad de F # para lidiar con la complejidad, aprendí mucho al leerlo, gracias
Peter McG
Gran respuesta Simon, y como Don mencionó anoche, citado en sus diapositivas recientes. ¿Es hora de agregar un enlace "agregar al carrito"?
Chris Ballard
1
hola, ¿puedes contarnos más sobre la arquitectura de tus aplicaciones?
Nikos
76

Durante mi pasantía en Microsoft Research, trabajé en algunas partes de Visual Studio IntelliSense para F # (que está escrito en F #). Ya tenía algo de experiencia con IntelliSense de proyectos anteriores de C #, así que creo que puedo comparar los dos.

  • Visual Studio Extensibility todavía se basa en COM, por lo que debe tratar con objetos que no son muy buenos .NET (y definitivamente no son funcionales), pero no creo que haya una diferencia importante entre C # y F # (funciona sin problemas de F #)

  • Las estructuras de datos utilizadas para representar el código del programa en F # son en su mayoría uniones discriminadas (que no se admiten en C # de manera razonable) y esto hace una gran diferencia para este tipo de aplicación (donde necesita procesar estructuras de árbol, como el código del programa ) Las uniones discriminadas y la coincidencia de patrones le permiten estructurar mejor el código (mantenga la funcionalidad relacionada en un lugar en lugar de tenerla en todos lados en métodos virtuales)

Anteriormente, también trabajé en el proveedor de CodeDOM para F # (también escrito en F #). De hecho, primero hice experimentos en C #, pero luego convertí el código a F #.

  • El proveedor de CodeDOM necesita atravesar alguna estructura representada usando objetos .NET, por lo que no hay mucho espacio para inventar sus propias representaciones de datos (que es el área donde F # puede ofrecer buenos beneficios).

  • Sin embargo, hubo muchas características pequeñas de F # que facilitaron la tarea. Como necesita producir una cadena, definí operadores personalizados para construir cadenas (usando StringBuilder) e implementé el código con ellas y funciones de orden superior (por ejemplo, para formatear la lista de objetos separados usando la cadena especificada, etc.), que eliminó una gran cantidad de repetición (y foreachbucles tediosos ).

Estos son dos ejemplos relativamente específicos, pero ambos están relacionados con el trabajo con representaciones de programas o expresiones, o más generalmente, estructuras de datos complejas en forma de árbol. Creo que en esta área, F # es definitivamente una buena opción (independientemente de las características funcionales en C #).

Tomás Petricek
fuente
66
Muy interesante, más evidencia de que la aceptación de F # en Microsoft es ciertamente alta, ¡qué gran pasantía debe haber sido!
Peter McG
43

Enviamos el primer producto comercial del mundo escrito en F # ( F # para visualización ) y el segundo ( F # para Numerics ), así como la primera literatura comercial sobre F # ( The F # .NET Journal ) y escribimos y publicamos el único libro sobre la versión actual de F # ( Visual F # 2010 para informática técnica ).

Habíamos enviado productos a lo largo de líneas similares escritas en C # (por ejemplo, esto ), pero también teníamos una sólida experiencia en el uso comercial de OCaml. Fuimos entusiastas de la adopción temprana de F # cuando todavía era un prototipo de investigación en 2006 porque reconocimos el potencial de tener un lenguaje moderno decente similar a OCaml en la plataforma .NET de fuerza industrial y, en consecuencia, presionamos para que se produjera. El resultado ha sido un éxito increíble y F # ha superado con creces nuestras elevadas expectativas.

Para nosotros, F # tiene muchas ventajas diferentes y lo usamos para una amplia variedad de aplicaciones. Tenemos cientos de miles de líneas de código F # en producción. Ahora usamos F # para todas nuestras aplicaciones LOB: nuestras transacciones con tarjeta de crédito se procesan usando el código F #, nuestras notificaciones de productos se envían usando el código F #, nuestras suscripciones se manejan usando el código F #, nuestras cuentas se hacen usando el código F # y así sucesivamente. Quizás la característica principal del idioma que paga dividendos aquí es la coincidencia de patrones. Incluso utilizamos F # para resaltar la sintaxis de color de nuestro último libro ...

Nuestra biblioteca de visualización es un gran vendedor y su funcionalidad se centra en la ejecución interactiva de F # en Visual Studio. Nuestra biblioteca aumenta esto con la capacidad de generar visualizaciones 2D y 3D interactivas con un esfuerzo mínimo (por ejemplo, soloPlot([Function sin], (-6., 6.))para trazar una onda sinusoidal). En particular, todos los problemas de subprocesos están completamente automatizados para que los usuarios no tengan que preocuparse por los subprocesos y el envío de la interfaz de usuario. Las funciones de primera clase y la pereza fueron extremadamente valiosas al escribir esta parte de la biblioteca y los tipos de datos algebraicos se usaron ampliamente en otros lugares. El rendimiento predecible también demostró ser valioso aquí cuando nuestros clientes encontraron errores de rendimiento en las pruebas de éxito de WPF y pudieron reimplementar fácilmente el código relevante en F # para una mejora de rendimiento de 10,000 ×. Debido a la naturaleza de forma libre de la GUI de este producto, el diseñador de la GUI y C # no habrían sido beneficiosos.

Gran parte de nuestro trabajo gira en torno a métodos numéricos, incluidas nuestras bibliotecas comerciales y libros. F # es mucho más fuerte en esta área que C # porque ofrece abstracciones de alto nivel (por ejemplo, funciones de orden superior) con penalizaciones de rendimiento mínimas. Nuestro resultado más convincente en este contexto fue la creación de una implementación simple pero generalizada de descomposición QR a partir de álgebra lineal que era 20 veces más corta que el código Fortran de la implementación de referencia de LAPACK, hasta 3 veces más rápida que la Intel Math ajustada por el proveedor Kernel Library y más genérico porque nuestro código puede manejar matrices de cualquier tipo, ¡incluso matrices simbólicas!

Actualmente estamos desarrollando componentes WPF / Silverlight en una combinación de F # (para las tripas) y C # (para la cuña), construyendo aplicaciones WPF para que actúen como manuales interactivos para nuestros productos de software y estoy escribiendo un nuevo libro, Multicore F #, que será la guía definitiva para la programación paralela de memoria compartida en .NET.

Jon Harrop
fuente
¿Eres el mismo Jon Harrop que escribió "F # para científicos"?
Andre Artus
77
Si. Escribí F # para científicos hace 5 años.
Jon Harrop
¿Tiene alguna referencia para el código de descomposición QR en F # que menciona en su penúltimo párrafo? Gracias.
Samik R
@SamikR: No, lo siento. Ese es el código comercial. Sin embargo, fue fácil de escribir.
Jon Harrop
@ ¿Alguna palabra sobre Multicore F #?
profesor bigglesworth
25

Durante los últimos 6 meses más o menos, he estado trabajando en una capa de emulación de Vim para Visual Studio 2010. Es un producto gratuito con toda la fuente que está disponible gratuitamente en github

El proyecto se divide en 3 DLL que representan una capa distinta. Cada capa tiene un dll de prueba de unidad correspondiente.

  1. Motor Vim: F #
  2. Capa WPF para adornos e integración de editor: C #
  3. Capa de integración de Visual Studio: C #

Este es el primer proyecto importante que hago con F # y debo decir que me encanta el idioma. En muchos sentidos, utilicé este proyecto como método de aprendizaje de F # (y esta curva de aprendizaje es muy evidente si nos fijamos en la historia del proyecto).

Lo que más me sorprende de F # es cuán conciso es un lenguaje. El motor Vim comprende la mayor parte de la lógica, pero solo comprende el 30% de la base de código general.

JaredPar
fuente
19
Editor ... lenguaje funcional ... emulación vi ... has reinventado emacs. NOOOOOOOOOOOOOOOOOOOOOOO!
Ben Voigt
2
Excepto que es "Certificado 100% sin paréntesis" :)
Pavel Minaev
@Pavel, excepto por las tuplas, por supuesto, y las llamadas al método .net
JaredPar,
26
Dos cosas a destacar aquí. En primer lugar, las tuplas no necesitan ()en F #: el ,operador es lo que las crea, por lo que ya let x = 1,2es una tupla válida sin ningún parente. En segundo lugar, cualquier par de pares en F # se puede reemplazar por pares de begin... end(esto se hereda de ML), por lo que, por ejemplo, "foo".IndexOf begin 'a', 1 endes una llamada de método .NET válida. Entonces, si alguna vez quisiste estar libre de padres, F # es un idioma que te permite hacer eso :)
Pavel Minaev
Comentario gracioso Pavel! No lo sabia. Creo que, en algunos casos con grandes bloques de agrupación, que en realidad podría preferir begin.. end. TAMBIÉN: ¡REGLAS VsVim!
Dan Fitch
13

Muchas de las pruebas unitarias para los componentes de F # Visual Studio están escritas en F #. Corren fuera de VS, burlándose de los diversos bits de Visual Studio. La capacidad de contraer objetos anónimos que implementan interfaces es útil en lugar de un marco / herramienta burlón. Solo puedo escribir

let owpe : string list ref = ref []
let vsOutputWindowPane = 
    { new IVsOutputWindowPane with
        member this.Activate () = err(__LINE__)
        member this.Clear () = owpe := []; 0
        member this.FlushToTaskList () = VSConstants.S_OK
        member this.GetName(pbstrPaneName) = err(__LINE__)
        member this.Hide () = err(__LINE__)
        member this.OutputString(pszOutputString) = owpe := pszOutputString :: !owpe ; 0
        member this.OutputStringThreadSafe(pszOutputString) = owpe := pszOutputString :: !owpe ; 0
        member this.OutputTaskItemString(pszOutputString, nPriority, nCategory, pszSubcategory, nBitmap, pszFilename, nLineNum, pszTaskItemText) = err(__LINE__)
        member this.OutputTaskItemStringEx(pszOutputString, nPriority, nCategory, pszSubcategory, nBitmap, pszFilename, nLineNum, pszTaskItemText, pszLookupKwd) = err(__LINE__)
        member this.SetName(pszPaneName) = err(__LINE__)
    }            
DoSomethingThatNeedsA(vsOutputWindowPane)
assert( !owpe = expectedOutputStringList )

cuando necesito una instancia de un ejemplo IVsOutputWindowPanede pasar a algún otro componente que eventualmente se llama OutputStringy Clear, a continuación, inspeccionar el string list refobjeto al final de la prueba para ver si el resultado esperado fue escrito.

Brian
fuente
Interesante, más evidencia de que la aceptación de F # dentro de Microsoft es ciertamente alta. No sabía que podía crear objetos anónimos que implementaran interfaces en F #
Peter McG
9

Escribimos un lenguaje de motor de reglas personalizado utilizando la implementación de Lex-Yacc en F #

EDITAR para incluir comentario respuesta

No hubo implementación de lex / yacc en C #. (hasta donde sabíamos, y el F # one era)

Hubiera sido posible, pero un verdadero dolor construir el análisis nosotros mismos.

Este tema muestra algunas otras sugerencias, como bibliotecas externas, pero nuestro arquitecto principal es un experto en lenguajes funcionales, por lo que la elección de usar F # fue obvia.

revs johnc
fuente
+1 Habría escrito esto anteriormente en C # ¿fue inadecuado o más lento por alguna razón?
Peter McG
@Peter McGrattan Al menos al momento de escribir (el software), no había implementación de lex / yacc en C #. Hubiera sido posible, pero un verdadero dolor construir el análisis nosotros mismos. stackoverflow.com/questions/540593/lex-yacc-for-c muestra algunas otras sugerencias, pero nuestro arquitecto principal es un experto en lenguajes funcionales, por lo que la elección de usar F # fue obvia
experto
si pensabas que no había lex / yacc para C #, tengo miedo de que simplemente no hayas buscado lo suficiente (hay uno más antiguo que F #) que dice que si necesitas lex / yacc, F # es, en mi opinión, mucho más adecuado martillo para ese clavo que c #
Rune FS
Yo mismo utilicé F # con fslex / fxyacc, aunque no en un proyecto de "producción" (no publicado aún, de todos modos): resaltado de sintaxis MSIL y extensión de finalización de código para VS. El principal beneficio de usar F # es que obtienes ADT, que son muy convenientes para representar árboles de análisis. Además, el uso de cremalleras ( en.wikipedia.org/wiki/Zipper_(data_structure) ) facilita la creación de lexing incremental, y las cremalleras, al ser funcionales, son más fáciles de manipular de forma concisa en F #.
Pavel Minaev
7

Actualmente estoy trabajando en una compilación para un lenguaje de programación. El compilador está escrito completamente en F #. El compilador (aparte de la construcción lex y parser con lex / yacc) es básicamente una gran transformación de una estructura compleja de árbol.

Como han señalado otros, discriminan las uniones y la coincidencia de patrones hace que trabajar con este tipo de estructura de datos sea mucho más fácil que descargar el código en métodos virtuales "por todas partes"

No había hecho ningún trabajo de F # antes de comenzar a trabajar en el compilador (sin embargo, tenía compiladores de buld en otra variante de OCaml llamada MoscowML) y justo como Jared dice que es visible desde el código qué partes hice primero, pero en general encontré F # fácil Sin embargo, aprender a volver a la mentalidad de FP después de codificar principalmente OO durante una década llevará un poco más de tiempo.

Al trabajar con árboles a un lado, encuentro que la capacidad de escribir código declarativo es el principal beneficio de que FP (incluido F # incluido) tenga un código que describa el algoritmo que estoy tratando de implementar en contraste con C # que describe cómo he implementado el algoritmo. Es una gran ventaja.

Runa FS
fuente
6

No es una experiencia personal, pero puedes escuchar un episodio de DNR (creo que es este ) donde hablan con la gente de Microsoft sobre F #. Escribieron la mayor parte del sistema de puntuación Xbox Live, que estaba lejos de ser trivial, usando F #. El sistema escalaba masivamente en cientos de máquinas y estaban muy satisfechos con él.

Igor Zevaka
fuente
5

No sé si está en producción, pero la IA de "The Path of Go" se escribió en F #:

http://research.microsoft.com/en-us/events/techvista2010/demolist.aspx#ThePathofGo

The Path of Go: un juego de investigación de Microsoft para Xbox 360

Esta demostración muestra un juego de Xbox 360, basado en el juego Go, producido internamente en Microsoft Research Cambridge. Go es uno de los juegos de mesa más famosos del este de Asia, se originó en China hace 4000 años. Detrás de la engañosa simplicidad del juego se esconde una gran complejidad. Solo toma unos minutos aprender, pero lleva toda una vida dominarlo. Aunque las computadoras han superado las habilidades humanas en Chess, implementar una IA competitiva para Go sigue siendo un desafío de investigación. El juego funciona con tres tecnologías desarrolladas en Microsoft Research Cambridge: una IA capaz de jugar Go, el lenguaje F # y TrueSkill ™ para que coincida con los jugadores en línea. La IA se implementa en F # y cumple con el desafío de ejecutarse eficientemente en el marco compacto .net en Xbox 360. Este juego te coloca en una serie de escenas 3D visualmente impresionantes. Fue completamente desarrollado en código administrado usando el entorno XNA.

(Alguien más mencionó "TrueSkill" ya).

Brian
fuente
Fascinante: F # ejecutándose en el marco compacto en XBox. ¿FSharp.Core.dll junto con FSharp.Core.optdata FSharp.Core.sigdata no hace referencia a ensamblajes que no son CF?
Peter McG
1
El CTP se entrega con un FSharp.Core separado que está construido para .NETCF. (También hay un FSharp.Core separado para Silverlight.)
Brian,
¿De qué CTP hablas?
Jwosty