¿Las bases de datos y la programación funcional están en desacuerdo?

122

He sido desarrollador web durante algún tiempo y recientemente comencé a aprender algo de programación funcional. Como otros, he tenido algunos problemas importantes para aplicar muchos de estos conceptos a mi trabajo profesional. Para mí, la razón principal de esto es que veo que un conflicto entre el objetivo de FP de permanecer apátrida parece estar en desacuerdo con el hecho de que la mayoría del trabajo de desarrollo web que he realizado ha estado fuertemente vinculado a las bases de datos, que están muy centradas en los datos.

Una cosa que me hizo un desarrollador mucho más productivo en el lado de OOP fue el descubrimiento de mapeadores relacionales de objetos como MyGeneration d00dads para .Net, Class :: DBI para perl, ActiveRecord para ruby, etc. Esto me permitió mantenerme alejado desde escribir declaraciones de inserción y selección todo el día, y enfocarse en trabajar con los datos fácilmente como objetos. Por supuesto, aún podía escribir consultas SQL cuando se necesitaba su poder, pero de lo contrario se resumía muy bien detrás de escena.

Ahora, volviendo a la programación funcional, parece que con muchos de los marcos web FP como Links requieren escribir mucho código sql repetitivo, como en este ejemplo . Weblocks parece un poco mejor, pero parece usar una especie de modelo OOP para trabajar con datos, y aún requiere que el código se escriba manualmente para cada tabla en su base de datos como en este ejemplo . Supongo que usas algo de generación de código para escribir estas funciones de mapeo, pero eso parece decididamente poco parecido.

(Tenga en cuenta que no he mirado los Weblocks o los enlaces con mucha atención, puede que no esté entendiendo cómo se usan).

Entonces, la pregunta es, para las porciones de acceso a la base de datos (que creo que son bastante grandes) de la aplicación web u otro desarrollo que requiere una interfaz con una base de datos sql, parece que nos vemos obligados a seguir una de las siguientes rutas:

  1. No use programación funcional
  2. Acceda a los datos de una manera molesta y sin abstracción que implica escribir manualmente una gran cantidad de código SQL o similar a SQL ala Enlaces
  3. Fuerce nuestro lenguaje funcional en un paradigma pseudo-OOP, eliminando así algo de la elegancia y la estabilidad de la verdadera programación funcional.

Claramente, ninguna de estas opciones parece ideal. ¿Ha encontrado una manera de sortear estos problemas? ¿Existe realmente un problema aquí?

Nota: Personalmente, estoy más familiarizado con LISP en el frente de FP, por lo que si desea dar algunos ejemplos y conocer varios idiomas de FP, es probable que lisp sea el idioma preferido de elección

PD: Para problemas específicos de otros aspectos del desarrollo web, vea esta pregunta .

Tristan Havelick
fuente
44
Echa un vistazo a ClojureQL y HaskellDB. Son capas de abstracción que utilizan álgebra relacional.
Masse
10
Estás comenzando con la premisa equivocada. La programación funcional tiene que ver con la gestión explícita y sensata del estado. Funcionan muy bien con bases de datos, de hecho.
Lucian
3
SQL es uno de los lenguajes enfocados en la programación funcional más exitosos, no creo que haya ninguna dificultad inherente.
Douglas
3
Tu # 2 y # 3 son una falsa dicotomía. Escribir SQL sin formato no es algo que deba evitarse necesariamente, y las abstracciones sobre una base de datos no necesariamente tienen que ser esquemáticas.
Dan Burton

Respuestas:

45

En primer lugar, no diría que CLOS (Common Lisp Object System) es "pseudo-OO". Es de primera clase OO.

En segundo lugar, creo que debe usar el paradigma que se ajuste a sus necesidades.

No puede almacenar datos sin estado, mientras que una función es flujo de datos y realmente no necesita estado.

Si tiene varias necesidades entremezcladas, mezcle sus paradigmas. No se limite a usar solo la esquina inferior derecha de su caja de herramientas.

Svante
fuente
3
solo por diversión, pensé en mencionar el registro de datos que intenta ser una base de datos más apátrida. registra todas las acciones, como "me gusta al usuario publicar 1233." Estas acciones se resuelven en el verdadero estado de la base de datos. La clave es que las consultas son solo hechos en lugar de mutación ...
Chet
80

Llegando a esto desde la perspectiva de una persona de base de datos, encuentro que los desarrolladores front-end se esfuerzan demasiado por encontrar formas de hacer que las bases de datos se ajusten a su modelo en lugar de considerar las formas más efectivas de usar bases de datos que no están orientadas a objetos o funcionales, sino que son relacionales y usan teoría de conjuntos. He visto que esto generalmente da como resultado un código de bajo rendimiento. Y además crea código que es difícil de ajustar.

Cuando se considera el acceso a la base de datos, hay tres consideraciones principales: integridad de los datos (por qué todas las reglas comerciales deben aplicarse a nivel de la base de datos, no a través de la interfaz de usuario), rendimiento y seguridad. SQL está escrito para administrar las dos primeras consideraciones de manera más efectiva que cualquier lenguaje front-end. Porque está específicamente diseñado para hacer eso. La tarea de una base de datos es muy diferente de la tarea de una interfaz de usuario. ¿Es de extrañar que el tipo de código que sea más efectivo en la gestión de la tarea sea conceptualmente diferente?

Y las bases de datos contienen información crítica para la supervivencia de una empresa. No es de extrañar que las empresas no estén dispuestas a experimentar con nuevos métodos cuando su supervivencia está en juego. Heck muchas empresas no están dispuestas a actualizar incluso a nuevas versiones de su base de datos existente. Por lo tanto, existe un conservadurismo inherente en el diseño de bases de datos. Y es así deliberadamente.

No trataría de escribir T-SQL o usar conceptos de diseño de bases de datos para crear su interfaz de usuario, ¿por qué trataría de usar su lenguaje de interfaz y conceptos de diseño para acceder a mi base de datos? ¿Porque crees que SQL no es lo suficientemente elegante (o nuevo)? ¿O no te sientes cómodo con eso? El hecho de que algo no se ajuste al modelo con el que se siente más cómodo no significa que sea malo o incorrecto. Significa que es diferente y probablemente diferente por una razón legítima. Utiliza una herramienta diferente para una tarea diferente.

HLGEM
fuente
"SQL está escrito para administrar las dos primeras consideraciones de manera más efectiva que cualquier lenguaje front-end". ¿Oh enserio? ¿Por qué, entonces, es que las restricciones de SQL todavía no pueden hacer cosas como esta ?
Robin Green
Pero un disparador puede, ese es uno de los propósitos principales de los disparadores para poder manejar restricciones complejas.
HLGEM
2
Me gustaría mover su último párrafo para que sea el párrafo principal. Muy buen punto, que se hace eco de lo que otros también están instando, que es un enfoque de paradigmas múltiples (no de talla única).
pesófago
31

Debería consultar el documento "Fuera del pozo de alquitrán" de Ben Moseley y Peter Marks, disponible aquí: "Fuera del pozo de alquitrán" (6 de febrero de 2006)

Es un clásico moderno que detalla un paradigma / sistema de programación llamado Programación Funcional-Relacional. Si bien no se relaciona directamente con las bases de datos, analiza cómo aislar las interacciones con el mundo exterior (bases de datos, por ejemplo) del núcleo funcional de un sistema.

El documento también analiza cómo implementar un sistema en el que el estado interno de la aplicación se define y modifica utilizando un álgebra relacional, que obviamente está relacionada con las bases de datos relacionales.

Este documento no dará una respuesta exacta sobre cómo integrar bases de datos y programación funcional, pero le ayudará a diseñar un sistema para minimizar el problema.

Kevin Albrecht
fuente
44
Que gran papel. El enlace que da está roto (¿temporalmente?), Pero encontré el documento también en shaffner.us/cs/papers/tarpit.pdf
pestophagous
2
@queque El enlace original aún está muerto. Puse el nuevo enlace en la respuesta de Kevin.
David Tonhofer
25
  1. Los lenguajes funcionales no tienen el objetivo de permanecer sin estado, tienen el objetivo de hacer explícita la gestión del estado. Por ejemplo, en Haskell, puede considerar la mónada estatal como el corazón del estado "normal" y la mónada IO una representación del estado que debe existir fuera del programa. Ambas mónadas le permiten (a) representar explícitamente acciones con estado y (b) construir acciones con estado componiéndolas usando herramientas transparentes referenciales.

  2. Usted hace referencia a una serie de ORM, que, por su nombre, resumen las bases de datos como conjuntos de objetos. En verdad, ¡esto no es lo que representa la información en una base de datos relacional! Por su nombre, representa datos relacionales. SQL es un álgebra (lenguaje) para manejar relaciones en un conjunto de datos relacionales y en realidad es bastante "funcional". Menciono esto para considerar que (a) los ORM no son la única forma de mapear la información de la base de datos, (b) que SQL es en realidad un lenguaje bastante agradable para algunos diseños de bases de datos, y (c) que los lenguajes funcionales a menudo tienen álgebra relacional mapeos que exponen el poder de SQL de una manera idiomática (y en el caso de Haskell, con verificación de tipo).

Yo diría que la mayoría de los lisps son el lenguaje funcional de un hombre pobre. Es totalmente capaz de usarse de acuerdo con las prácticas funcionales modernas, pero dado que no las requiere, es menos probable que la comunidad las use. Esto conduce a una mezcla de métodos que pueden ser muy útiles, pero ciertamente oscurecen la forma en que las interfaces funcionales puras aún pueden usar bases de datos de manera significativa.

J. Abrahamson
fuente
15

No creo que la naturaleza sin estado de los lenguajes fp sea un problema para conectarse a bases de datos. Lisp es un lenguaje de programación funcional no puro, por lo que no debería tener ningún problema con el estado. Y los lenguajes de programación funcionales puros como Haskell tienen formas de lidiar con las entradas y salidas que se pueden aplicar al uso de bases de datos.

A partir de su pregunta, parece que su principal problema radica en encontrar una buena manera de abstraer los datos basados ​​en registros que obtiene de su base de datos en algo que es lisp-y (¿lisp-ish?) Sin tener que escribir mucho SQL código. Esto parece más un problema con las herramientas / bibliotecas que un problema con el paradigma del lenguaje. Si quieres hacer FP puro, tal vez lisp no sea el lenguaje adecuado para ti. El lisp común parece más sobre integrar buenas ideas de oo, fp y otros paradigmas que sobre fp puro. Tal vez deberías estar usando Erlang o Haskell si quieres ir a la ruta FP pura.

Creo que las ideas de 'pseudo-oo' en lisp también tienen su mérito. Es posible que desee probarlos. Si no se ajustan a la forma en que desea trabajar con sus datos, puede intentar crear una capa sobre Weblocks que le permita trabajar con sus datos de la manera que desee. Esto podría ser más fácil que escribir todo usted mismo.

Descargo de responsabilidad: no soy un experto de Lisp. Estoy principalmente interesado en los lenguajes de programación y he estado jugando con Lisp / CLOS, Scheme, Erlang, Python y un poco de Ruby. En la vida diaria de programación todavía me veo obligado a usar C #.

Mendelt
fuente
3
Erlang no es FP puro por ninguna definición de la palabra. Escribes erlang creando muchos procesos (todos ejecutándose en paralelo) que se envían mensajes entre sí, al igual que los objetos en, por ejemplo, smalltalk. Entonces, desde una perspectiva de alto nivel, incluso puede parecer algo OO-ish, y definitivamente tiene estado. Si amplía (en el código que se ejecuta dentro de un proceso) se ve más funcional, pero aún no es puramente funcional, ya que puede enviar mensajes (y, por lo tanto, E / S, etc.) desde cualquier lugar que desee, así como almacenar " variables globales "(global al proceso, dentro de algo llamado" dict proceso ")
Amadiro
@Amadiro "definitivamente tiene estado". Claro que lo hace. Siempre tenemos estado. El problema no es el estado, es un estado mutable . Una buena parte de la "programación funcional" se trata de deshacerse de las representaciones de estado que son frágiles (por ejemplo, instancias de objetos que se modifican por otros procesos mientras tenemos una referencia a ellos, de una manera no transaccional para agregar insulto a la lesión). Erlang tiene un estado no mutable y, por lo tanto, cumple con este criterio de programación funcional. Y así: las bases de datos de cualquier tipo nunca son un problema. Base de datos actualizaciones son un problema (véase también el desagradable afirman en Prolog).
David Tonhofer
15

Si su base de datos no destruye la información, entonces puede trabajar con ella de una manera funcional consistente con los valores de programación "puramente funcionales" trabajando en funciones de la base de datos completa como un valor.

Si en el momento T la base de datos dice que "a Bob le gusta Suzie", y tuviste una función que le gustó y aceptó una base de datos y un me gusta, entonces mientras puedas recuperar la base de datos en el momento T, tienes un programa funcional puro que involucra una base de datos . p.ej

# Start: Time T
likes(db, "Bob")
=> "Suzie"
# Change who bob likes
...
likes(db "Bob")
=> "Alice"
# Recover the database from T
db = getDb(T)
likes(db, "Bob")
=> "Suzie"

Para hacer esto, nunca puede tirar la información que podría usar (lo que en la práctica significa que no puede tirar la información), por lo que sus necesidades de almacenamiento aumentarán monotónicamente. Pero puede comenzar a trabajar con su base de datos como una serie lineal de valores discretos, donde los valores posteriores están relacionados con los anteriores a través de transacciones.

Esta es la idea principal detrás de Datomic , por ejemplo.

animal
fuente
Agradable. Ni siquiera sabía sobre Datomic. Ver también: justificación de Datomic .
David Tonhofer
12

De ningún modo. Hay un género de bases de datos conocido como 'Bases de datos funcionales', de las cuales Mnesia es quizás el ejemplo más accesible. El principio básico es que la programación funcional es declarativa, por lo que se puede optimizar. Puede implementar una unión usando List Comprehensions en colecciones persistentes y el optimizador de consultas puede determinar automáticamente cómo implementar el acceso al disco.

Mnesia está escrito en Erlang y hay al menos un marco web ( Erlyweb ) disponible para esa plataforma. Erlang es intrínsecamente paralelo con un modelo de subprocesamiento de nada compartido, por lo que, en cierto modo, se presta a arquitecturas escalables.

Preocupado por TunbridgeWells
fuente
1
No creo que sea una gran solución. También hay bases de datos orientadas a objetos, pero por lo general, desea conectarse a una base de datos SQL relacional antigua.
jalf
44
Todavía tiene una falta de coincidencia de impedancia con los lenguajes y bases de datos OO de la misma manera que tiene una falta de coincidencia de impedancia funcional de SQL.
Preocupado por
1
@ConcernedOfTunbridgeWells Declararé arbitrariamente que este desajuste de impedancia es un producto de la imaginación de las personas con martillos que necesitan todo para ser clavos. Las capas muy delgadas y el conocimiento sobre SQL pueden recorrer un largo camino con elegancia, por lo tanto, jOOQ y cuñas similares.
David Tonhofer
6

Una base de datos es la manera perfecta de realizar un seguimiento del estado en una API sin estado. Si se suscribe a REST, su objetivo es escribir código sin estado que interactúe con un almacén de datos (o algún otro servidor) que realice un seguimiento de la información de estado de manera transparente para que su cliente no tenga que hacerlo.

La idea de un asignador relacional de objetos, donde importa un registro de base de datos como un objeto y luego lo modifica, es tan aplicable y útil para la programación funcional como para la programación orientada a objetos. La única advertencia es que la programación funcional no modifica el objeto en su lugar, pero la API de la base de datos puede permitirle modificar el registro en su lugar. El flujo de control de su cliente se vería así:

  • Importe el registro como un objeto (la API de la base de datos puede bloquear el registro en este punto),
  • Lea el objeto y la rama según su contenido como desee,
  • Empaquete un nuevo objeto con sus modificaciones deseadas,
  • Pase el nuevo objeto a la llamada API apropiada que actualiza el registro en la base de datos.

La base de datos actualizará el registro con sus cambios. La programación funcional pura podría no permitir la reasignación de variables dentro del alcance de su programa , pero la API de su base de datos aún puede permitir actualizaciones en el lugar.

Brice frito
fuente
5

Me siento más cómodo con Haskell. El marco web más destacado de Haskell (comparable a Rails y Django) se llama Yesod. Parece tener un ORM bastante genial, seguro para los tipos y de backend múltiple. Echa un vistazo al capítulo Persistencia en su libro.

Honza Pokorny
fuente
0

Las bases de datos y la programación funcional pueden fusionarse.

por ejemplo:

Clojure es un lenguaje de programación funcional basado en la teoría de bases de datos relacionales.

               Clojure -> DBMS, Super Foxpro
                   STM -> TransactionMVCC
Persistent Collections -> db, table, col
              hash-map -> indexed data
                 Watch -> trigger, log
                  Spec -> constraint
              Core API -> SQL, Built-in function
              function -> Stored Procedure
             Meta Data -> System Table

Nota: En la última especificación2, la especificación se parece más a RMDB. ver: spec-alpha2 wiki: Schema-and-select

Yo defiendo: construir un modelo de datos relacionales sobre el mapa hash para lograr una combinación de ventajas NoSQL y RMDB. Esta es en realidad una implementación inversa de posgtresql.

Mecanografía de pato: si parece un pato y grazna como un pato, debe ser un pato.

Si el modelo de datos de clojure como un RMDB, las instalaciones de clojure como un RMDB y la manipulación de datos de clojure como un RMDB, clojure debe ser un RMDB.

Clojure es un lenguaje de programación funcional basado en la teoría de bases de datos relacionales

Todo es RMDB

Implemente un modelo de datos relacionales y una programación basada en hash-map (NoSQL)

Lin Pengcheng
fuente