Mi empresa me pidió que escribiera una aplicación personalizada que permitiera a los usuarios realizar consultas ad hoc en una base de datos de archivos planos. Los usuarios de esta aplicación eran los tipos típicos de Joe Empresario. No son programadores, y es poco probable que hayan visto una declaración SQL en sus vidas.
Como resultado, tuve la tarea de desarrollar una interfaz de usuario amigable que permitiera a los usuarios seleccionar columnas, tablas, condiciones, etc. para crear una consulta. Esto es un desafío porque puedo representar la declaración de SQL en la interfaz de usuario sin crear primero una representación abstracta de la misma en la memoria.
La primera iteración fue escrita en C#. He creado una clases bote lleno para representar la sintaxis abstracta de una instrucción SQL, lo que dio lugar a un modelo de objetos muy engorroso:
- una Participar en clase, una se une a clase de colección
- una clase WhereClause, una clase de colección WhereClauses
- una clase SelectedColumn, selectedColumns clase de colección
- una clase OrderBy, OrderBy colecciones de recogida clase
- una clase SqlStatement que agrupa todas las clases aforemtioned juntos
La conversión de una instancia de SqlStatement a una cadena fue gloriosamente dolorosa, fea y con errores. Mover la dirección opuesta, de cadena a SqlStatement, fue aún peor, ya que rompió las piezas de una cadena de SQL utilizando mucha manipulación de expresiones regulares y cadenas.
Arranqué el sistema, producí una aplicación que funcionó, pero no estaba muy contento con ella. Especialmente no sucedió cuando los requisitos comerciales de la aplicación cambiaron en mí, lo que me obligó a volver a visitar mi código C#.
Así como un experimento, Reescribí mi SqlStatement en Fa # y representado como una unión:
type dir = Asc | Desc
type op = Eq | Gt | Gte | Lt | Lte
type join = Inner | Left | Right
type sqlStatement =
| SelectedColumns of string list
| Joins of (string * join) list
| Wheres of (string * op * string) list
| OrderBys of (string * dir) list
type query = SelectedColumns * Joins * Wheres * OrderBys
Esa pequeña cantidad de código reemplazado unos pocos cientos de líneas de C# y una docena de clases. Más importante aún, la coincidencia de patrones simplificó el proceso requerido para convertir la representación abstracta en una cadena SQL.
La parte divertida fue convertir una cadena SQL de nuevo en un objeto de consulta usando fslex/fsyacc.
Si mal no recuerdo, el código original de C# totalizó 600 líneas y alrededor de una docena de clases, muchas expresiones regulares confusas y requirió dos días para escribir y probar. En comparación, el código F # consistía en un archivo .fs de alrededor de 40 líneas, 100 líneas más o menos para implementar el analizador/analizador lexer, y consumía algunas horas de mi día para probar.
En serio, escribir esta parte de la aplicación en F # parecía una trampa, así de fácil resultó.
¿Podría aclarar qué quiere decir con "matemático"? ¿Te refieres a "numérico"? –
Gracias. Sí. Esa es la cantidad de matemáticas que he olvidado desde la universidad;) – krosenvold
A cada publicación de este tipo le falta el único superconjunto de respuestas: Datos. La programación funcional está destinada a hacer el procesamiento de un conjunto de datos. La gente confunde esto con las matemáticas porque las matemáticas complejas a menudo se aplican a los conjuntos de datos. Todo el mundo menciona la concurrencia, que de nuevo es un mecanismo para procesar un conjunto de datos. La gente dice analizadores, de nuevo, procesando un conjunto de datos. El hecho de que las listas de comprensión incluso existen debería ser suficiente para señalar, estos lenguajes están completa y completamente construidos con el propósito de trabajar con conjuntos de datos. Que están creciendo en estos días, y por qué FP ahora importa. –