Me las arreglé para entender la definición de la clase. MonadReader
class Monad m => MonadReader r m | m -> r where
...
Después de leer el documento de Dependencia funcional en Haskell, ahora puedo entender que | m -> respecifica que la variable de tipo rse decide de forma exclusiva m. Creo que este requisito es razonable en función de las pocas instancias típicas de MonadReader que he visto hasta ahora (por ejemplo Reader), pero me parece que todavía podemos definir instancias como Readerincluso sin esta cláusula de dependencia funcional.
Mi pregunta es ¿por qué necesitamos dependencia funcional en la definición de MonadReader? ¿Es esto funcionalmente necesario para definir MonadReader en el sentido de que MonadReader no se puede definir adecuadamente sin él, o es simplemente una restricción para limitar las formas en que MonadReader puede usarse para que las instancias de MonadReader se comporten de una manera esperada?
fuente

MonadReader; Es necesario para usar convenientementeMonadReader.Respuestas:
Es necesario para que la inferencia de tipos funcione de una manera que sea más conveniente para el usuario.
Por ejemplo, sin el fundep esto no compilaría:
Para hacer la compilación anterior necesitaríamos escribir
Esto es porque, sin el fundep, el compilador no puede inferir que
xes unInt. Después de todo, una mónadaReadertT Int IOpodría tener múltiples instanciasentonces el programador debe proporcionar alguna anotación que fuerce
x :: Int, o el código es ambiguo.fuente
Esto no es realmente una respuesta, pero es demasiado largo para un comentario. Tienes razón en que es posible definir la
MonadReaderclase sin un fundep. En particular, la firma de tipo de cada método determina cada parámetro de clase. Sería bastante posible definir una jerarquía más fina.El principal problema con este enfoque es que los usuarios tienen que escribir un montón de instancias.
fuente
Creo que la fuente de confusión es que en la definición de
Se asume implícitamente que se
mcontiene arsí mismo (para instancias comunes). Déjame usar una definición más ligera deReadercomoCuando
rse elige el parámetro, puede definir fácilmente una instancia de mónada paraReader r. Eso significa que en la definición de clase de tipo semdebe sustituirReader r. Así que mira cómo la expresión termina siendo:Pero, ¿por qué necesitamos esto? Mira la definición de
askdentro de laMonadReaderclase.Sin el fun-dep nada podría detenerme por definir
askuna forma de devolver un tipo diferente como el estado. Aún más, podría definir muchas instancias de lector de mónada para mi tipo. Como ejemplo, estas serían definiciones válidas sin func-depEntonces, si tuviera un valor,
val :: ReaderT Int IO Double¿cuál sería el resultadoask? Tendríamos que especificar una firma de tipo como se muestra a continuaciónAdemás de no tener sentido, no es conveniente especificar el tipo una y otra vez.
Como conclusión, utilizando la definición real de
ReaderT. Cuando tiene algo como queval :: ReaderT String IO Intla dependencia funcional dice: Tal tipo podría tener solo una instancia única deMonadReadertypeclass que se define como la que usaStringcomorfuente