2010-11-30 15 views
7

Digamos que queremos usar ReaderT [(a,b)] sobre la mónada Maybe, y luego queremos hacer una búsqueda en la lista.¿Las funciones de envoltura en un transformador de mónada se deben considerar como malas prácticas?

Ahora una manera fácil, y no demasiado raro esto es:

primera posibilidad

find a = ReaderT (lookup a) 

Sin embargo, parece como éste afirma algo no trivial acerca de cómo funciona el transformador ReaderT . Si miramos el código fuente de Control.Monad.Reader, queda claro que esto funciona bien. Pero no he leído ninguna documentación que respalde esto. Sin embargo, también podríamos escribir encontrar de esta manera:

segunda posibilidad

find a = do y <- ask 
      lift (lookup a y) 

Ideas similares se aplican para envolver MaybeT, StateT, State y Reader. Normalmente escribo algo así como el primer ejemplo, pero la mayoría de las veces es muy obvio cómo escribirlo como el segundo ejemplo, y hasta podrías decir que es más legible. Entonces mi pregunta es: ¿debería el código como el primer ejemplo considerarse malo?

+2

También puede escribir 'find a = lift. búsqueda a = << preguntar', que es tan claro (en mi humilde opinión) como la segunda opción, pero es más corto. –

+0

o use fmap: encuentre a = fmap (busque una) pregunte = busque una <$> pregunte – urso

+0

Es una mierda que dejen de exportar el constructor – fuz

Respuesta

3

La versión actual de la biblioteca mtl - que se basa en la biblioteca de transformadores - exporta la función reader :: (r -> a) -> Reader r a precisamente para este propósito cuando se utiliza la sencilla Reader mónada. Entonces vemos que el diseño de la biblioteca tiene en cuenta este uso. Como no se proporciona dicha función para ReaderT, podemos decir con cierta seguridad que la forma oficialmente admitida de hacerlo con ReaderT es usar el constructor directamente.

Estoy de acuerdo con usted si usted dice que un análogo readerT :: Monad m => (r -> a) -> ReaderT r m a debe agregarse a la biblioteca.Sería bueno tanto por coherencia como por permitir la posibilidad de cambiar la representación interna algún día sin romper el código de nadie.

Pero por ahora, su "primera posibilidad" es el camino a seguir.

9

Creo que el mayor problema con la primera forma es:

Si los autores MTL (o lo que sea transformador de la biblioteca que usa), deciden dejar de exportar el constructor de datos para ReaderT entonces dejará de funcionar. Esto sucedió con la mónada de estado en el bache de versión de mtl 1 a mtl 2 y es bastante molesto. Mientras que, ask es parte de la API oficial de Reader y debe planear que se quede.

Por otro lado, no consideraría la primera forma incorrecta.

+0

La mónada de estado todavía está disponible con el constructor. Creo que te refieres a la 'ST'-mónada. – fuz

+2

Si miras aquí: http://hackage.haskell.org/packages/archive/mtl/2.0.1.0/doc/html/src/Control-Monad-State-Lazy.html verás que el constructor de datos para State ya no se exporta Es cierto que puedes hacer muchas cosas para solucionar esto. –

3

Al menos hay una diferencia de velocidad.

Escribí un program, que usa un gen aleatorio como un estado y debe generar unos 5000000 valores aleatorios mientras se ejecuta. Consideremos ahora estas dos funciones, que ruedan un dado:

random16 = State $ randomR (1,6) -- Using the internal representation 
random16' = do 
      s <- get 
      (r,s') <- randomR (1,6) s 
      put s' 
      return r 

con el primero de ellos, el programa se ejecuta en aproximadamente 6 segundos, mientras que el segundo es mucho más lento, teniendo unos 8 segundos. Puedo crear una imagen, que es similar para el lector, así que tal vez use esta en lugar de la más clara cuando el tiempo de ejecución es importante. Usé la versión estricta para esto.

Cuestiones relacionadas