Estoy buscando escribir un módulo genérico que permita a los programas de Haskell interactuar con Cassandra. El módulo necesitará mantener su propio estado. Por ejemplo, tendrá un grupo de conexiones y una lista de devoluciones de llamadas que se invocarán cuando se guarde un nuevo registro. ¿Cómo debería estructurar el código para que este módulo pueda mantener su estado? Estos son algunos de los enfoques que he estado considerando. ¿Estoy en el camino correcto? (Soy nuevo en Haskell y todavía está aprendiendo las mejores maneras de que funcionalmente.)¿Cómo se estructura un módulo con estado en Haskell?
Opción 1:
El módulo se ejecuta en una mónada (s Statet IO), donde s es el estado global de la totalidad programa usando el módulo Cassandra. Por supuesto, dado que el módulo de Cassandra podría ser utilizado por múltiples programas, los detalles de lo que hay en s deberían ser invisibles para el módulo de Cassandra. El módulo tendría que exportar una clase de tipo que le permitiera extraer CassandraState de s y volver a insertar un nuevo CassandraState en s. Entonces, cualquier programa que use el módulo debería hacer que su estado principal sea miembro de esta clase de tipos.
Opción 2:
El módulo se ejecuta en una mónada (Statet CassandraState IO). Cada vez que alguien invoca una acción en el módulo, debe extraer CassandraState de donde sea que esté escondido, invocar la acción con runState, tomar el estado resultante y esconderlo de nuevo (donde sea).
Opción 3:
No ponga las funciones del módulo de Cassandra en una mónada Statet en absoluto. En su lugar, haga que la persona que llama pase explícitamente en CassandraState cuando sea necesario. El problema con la opción 2 es que no todas las funciones en el módulo modificarán el estado. Por ejemplo, obtener una conexión modificará el estado y requerirá que la persona que llama oculte el estado resultante. Pero, para guardar un nuevo registro, es necesario leer el estado (para obtener las devoluciones de llamada), pero no es necesario cambiar el estado. La opción 2 no le da a la persona que llama ninguna pista de que la conexión cambia el estado mientras que crear no.
Pero, si dejo de usar la mónada StateT y solo tengo funciones que toman en estados como parámetros y devuelven valores simples o tuplas de valores simples y nuevos estados, entonces es realmente obvio para quien llama cuando el estado lo necesita para ser salvado (Bajo las cubiertas de mi módulo, tomaría los estados entrantes y los construiría en una mónada (StateT CassandraState IO), pero los detalles de esto quedarían ocultos para la persona que llama. Por lo tanto, para la persona que llama, la interfaz es muy explícita. , pero bajo las sábanas, es sólo la opción 2.)
Opción 4:
Algo más?
Este problema debe aparecer con bastante frecuencia cuando se construyen módulos reutilizables. ¿Hay algún tipo de forma estándar para resolverlo?
(Por cierto, si alguien sabe una mejor manera de interactuar con Cassandra de Haskell que el uso de Ahorro, por favor hágamelo saber! Tal vez no tengo que escribir esto en absoluto. :-)
FYI - en Haskell circles 'module' es la unidad de compilación, es decir, un único archivo fuente. Aunque realmente no tengo un nombre mejor para lo que describes, hablar de un "módulo" con estado me echó por un momento. –
Vaya. Debería haber dicho 'paquete' o 'biblioteca'. –