cref - ¿En qué áreas podría ser más apropiado el uso de F#que C#?
remarks c# (11)
En los últimos años, F # se ha convertido en uno de los lenguajes totalmente compatibles de Microsoft que emplean muchas ideas incubadas en OCaml, ML y Haskell.
En los últimos años, C # ha ampliado sus funciones de propósito general al introducir más y más funciones de lenguaje funcional: LINQ (comprensión de lista), 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 las bibliotecas de marcos o cambiar el estado compartido cuando se llama una función), existe una gran similitud entre los dos idiomas, aunque cada uno tiene su propia función. polar propio de énfasis primario opuesto.
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 cliente, aplicaciones de servidor) que ha escrito en F # en el último año o lo que anteriormente tendría escrito en C #.
Actualmente estoy trabajando en una compilación para un lenguaje de programación. El compilador está escrito enteramente en F #. El compilador (aparte de la compilación de lex y analizador con lex / yacc) se construye básicamente como una gran cantidad de transformación de una estructura compleja similar a un árbol.
Como han señalado otros, discriminar 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 empezar a trabajar en el compilador (sin embargo, tenía dos compiladores en otra variante de OCaml llamada MoscowML) y, justo cuando Jared dice que es visible desde el código, qué partes hice primero, pero en general encontré que F # es fácil. Sin embargo, aprender un poco más sobre cómo llegar a la mentalidad de FP después de codificar principalmente OO durante una década llevará un poco más de tiempo.
trabajando con árboles a un lado, creo que la capacidad de escribir código declarativo es el principal beneficio de FP (incluido F #) que tiene un código que describe el algoritmo que estoy intentando implementar en contraste con C # que describe cómo implementé el algoritmo es una gran ventaja.
Aquí hay un estudio de caso sobre un banco que usa F # junto con C ++ / COM para cosas:
http://www.microsoft.com/casestudies/Case_Study_Detail.aspx?CaseStudyID=4000006794
Durante los últimos 6 o más meses, he estado trabajando en una capa de emulación Vim para Visual Studio 2010. Es un producto gratuito con toda la fuente que está disponible gratuitamente en github.
- GitHub: http://github.com/jaredpar/VsVim
- VsVim en Visual Studio Gallery
El proyecto se divide en 3 DLL que representan una capa distinta. Cada capa tiene una unidad de prueba correspondiente dll.
- Motor Vim: F #
- Capa WPF para adornos e integración de editor: C #
- Capa de integración de Visual Studio: C #
Este es el primer proyecto importante que he hecho con F # y tengo que decir que me encanta el idioma. En muchos sentidos, utilicé este proyecto como un método de aprendizaje F # (y esta curva de aprendizaje es muy evidente si observa la historia del proyecto).
Lo que más me sorprende de F # es lo conciso de un idioma que es. El motor Vim comprende la mayor parte de la lógica, pero solo comprende el 30% de la base de código general.
Durante mi pasantía en Microsoft Research, trabajé en algunas partes de Visual Studio IntelliSense para F # (que a su vez 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 aún se basa en COM, por lo que necesita lidiar con objetos que no son objetos .NET no muy agradables (y definitivamente no son funcionales), pero no siento que haya una diferencia importante entre C # y F # (funciona sin problemas) de F #)
Las estructuras de datos utilizadas para representar el código de programa en F # son en su mayoría uniones discriminadas (que no son compatibles con 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 de programa ). Las uniones discriminadas y la coincidencia de patrones le permiten estructurar mejor el código (mantener la funcionalidad relacionada en un lugar en lugar de tenerlo todo en el lugar en métodos virtuales)
Anteriormente, también trabajé en el proveedor de CodeDOM para F # (también escrito en F #). De hecho, hice primero experimentos en C #, pero luego convertí el código a F #.
El proveedor de CodeDOM necesita atravesar una 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, había muchas características pequeñas de F # que hacían la tarea más fácil. Ya que necesita producir una cadena, definí operadores personalizados para construir cadenas (usando
StringBuilder
) e implementé el código usándolos y funciones de orden superior (por ejemplo, para formatear una lista de objetos separados usando la cadena especificada, etc.), que eliminó mucho de repetición (y tediosa para cada bucle).
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, con estructuras de datos complejas tipo árbol. Creo que en esta área, F # es definitivamente una buena opción (independientemente de las características funcionales en C #).
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 estado enviando productos siguiendo líneas similares escritas en C # (por ejemplo, this ), pero también teníamos una sólida experiencia en el uso comercial de OCaml. Fuimos entusiastas en la adopción de F # cuando aún era un prototipo de investigación en 2006 porque reconocimos el potencial de tener un lenguaje moderno y decente de estilo 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 altas 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 con el código F #, nuestras notificaciones de productos se envían con el código F #, nuestras suscripciones se manejan con el código F #, nuestras cuentas se realizan con el código F #, etc. Quizás la característica principal del lenguaje que paga dividendos aquí es la coincidencia de patrones. Incluso usamos F # para colorear la sintaxis de nuestro último libro ...
Nuestra biblioteca de visualización es muy vendida 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 interactivas en 2D y 3D con un esfuerzo mínimo (por ejemplo, solo Plot([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 IU. Las funciones de primera clase y la pereza eran extremadamente valiosas al escribir esta parte de la biblioteca y los tipos de datos algebraicos se usaban ampliamente en otros lugares. El rendimiento predecible también demostró ser valioso aquí cuando nuestros clientes detectaron errores de rendimiento en las pruebas de impacto de WPF y pudieron fácilmente volver a implementar 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 nuestros 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 la descomposición QR del álgebra lineal que fue 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 sintonizada por el proveedor. Kernel Library y más genéricos 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 el shim), creando 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.
Escribimos un lenguaje de motor de reglas personalizado utilizando la implementación Lex-Yacc en F #
EDITAR para incluir comentario respuesta
No hubo implementación de lex / yacc en C #. (Por lo que nosotros sabíamos, y el F # uno 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 una tarea sencilla.
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 del servidor estaban en C #, pero el motor de cálculo se escribió en F #.
El uso de F # para abordar la complejidad en el corazón de esta aplicación demuestra claramente un punto dulce para el lenguaje dentro del software empresarial, a saber, 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) trataban con unidades de tiempo, poder y energía. Hacer que el sistema de tipo verifique la corrección 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 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 bucle de edición / compilación / ejecución / prueba más tradicional. Es una forma muy natural para que un programador desarrolle su comprensión del problema y las tensiones de diseño en juego.
Prueba de unidad El código escrito con funciones que no tienen efectos secundarios y estructuras de datos inmutables es una alegría para probar. No hay interacciones complejas dependientes del tiempo para arruinar las cosas o conjuntos grandes de dependencias para ser burlados.
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 luego inyectarse en cualquier módulo de C # que necesitara usarlo sin ninguna preocupación sobre la interoperabilidad. Sin costura. El programador de C # no necesita saber nunca.
Reducción de código Gran parte de los datos introducidos en el motor de cálculo se realizó en forma de vectores y matrices. Las funciones de orden superior se comen en el desayuno con un mínimo esfuerzo, un código mínimo. Hermoso.
Falta de errores La programación funcional puede parecer extraña. Puedo trabajar en un algoritmo, esforzándome para que el código pase el comprobador de tipos, pero una vez que el comprobador de tipos está satisfecho, funciona. Es casi binario, no compilará o es correcto. Los errores extraños de casos de borde se minimizan, la recursión y las funciones de orden superior eliminan una gran cantidad de códigos de contabilidad que introducen errores de casos de borde.
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.
La gente de WebSharper ha creado un producto completo centrado en F # para la programación web. Aquí hay un artículo que habla de ello:
Muchas de las pruebas unitarias para los componentes de F # Visual Studio están escritas en F #. Se ejecutan fuera de VS, burlándose de los diversos bits de Visual Studio. La capacidad de configurar objetos anónimos que implementan interfaces es útil en lugar de un marco / herramienta de burla. 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, por ejemplo, un IVsOutputWindowPane
para pasar a algún otro componente que finalmente llamará a OutputString
y Clear
, y luego inspeccionar el objeto de string list ref
al final de la prueba para ver si se escribió la salida esperada.
No es una experiencia personal, pero puedes escuchar un episodio de DNR (creo que es este ) donde hablan con gente de Microsoft sobre F #. Escribieron la mayor parte del sistema de puntuación de Xbox Live, que estaba lejos de ser trivial, utilizando F #. El sistema se extendió masivamente a través de cientos de máquinas y estaban muy satisfechos con él.
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 de 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 dominar. Aunque las computadoras han superado las habilidades humanas en Chess, la implementación de una IA competitiva para Go sigue siendo un desafío de investigación. El juego se basa en tres tecnologías desarrolladas en Microsoft Research Cambridge: una IA capaz de jugar Go, el lenguaje F # y TrueSkill ™ para emparejar jugadores en línea. La IA se implementa en F # y cumple con el desafío de correr de manera eficiente en el marco compacto de .net en Xbox 360. Este juego te coloca en una serie de escenas 3D visualmente impresionantes. Fue desarrollado completamente en código administrado usando el entorno XNA.
(Alguien más mencionó "TrueSkill" ya.)