Eu apenas consegui entender a definição da classe MonadReader
class Monad m => MonadReader r m | m -> r where
...
Depois de ler o documento de Dependência funcional em Haskell, agora posso entender que | m -> r
especifica que a variável de tipo r
é decidida exclusivamente por m
. Eu acho que esse requisito é razoável com base nas poucas instâncias típicas do MonadReader que eu vi até agora (por exemplo Reader
), mas parece-me que ainda podemos definir instâncias como Reader
mesmo sem essa cláusula de dependência funcional.
Minha pergunta é por que precisamos de dependência funcional na definição do MonadReader? Isso é funcionalmente necessário para definir o MonadReader no sentido de que o MonadReader não pode ser definido adequadamente sem ele, ou é apenas uma restrição limitar as maneiras como o MonadReader pode ser usado para que as instâncias do MonadReader se comportem da maneira esperada?
fonte
MonadReader
; é necessário para o uso convenienteMonadReader
.Respostas:
É necessário fazer com que a inferência de tipo funcione de maneira mais conveniente para o usuário.
Por exemplo, sem o fundep, isso não seria compilado:
Para fazer a compilação acima, precisaríamos escrever
Isso ocorre porque, sem o fundep, o compilador não pode inferir que
x
é umInt
. Afinal, uma mônadaReadertT Int IO
pode ter várias instânciasportanto, o programador deve fornecer uma anotação que força
x :: Int
, ou o código é ambíguo.fonte
Esta não é realmente uma resposta, mas é muito tempo para um comentário. Você está certo de que é possível definir a
MonadReader
classe sem um fundep. Em particular, a assinatura de tipo de cada método determina todos os parâmetros de classe. Seria perfeitamente possível definir uma hierarquia mais fina.O principal problema dessa abordagem é que os usuários precisam escrever várias instâncias.
fonte
Eu acho que a fonte de confusão é que, na definição de
É implicitamente assumido que se
m
contémr
(para instâncias comuns). Deixe-me usar um definiton mais claro deReader
comoQuando o
r
parâmetro é escolhido, você pode definir facilmente uma instância de mônada paraReader r
. Isso significa que na definição de classe de tipom
deve ser substituídaReader r
. Então, veja como a expressão acaba sendo:Mas por que precisamos disso? Veja a definição de
ask
dentro daMonadReader
classe.Sem a diversão-dep nada poderia me parar para definir
ask
um tipo diferente de estado. Ainda mais, eu poderia definir muitas instâncias do leitor de mônada para o meu tipo. Como exemplo, isso seria definições válidas sem func-depEntão, se eu tivesse um valor
val :: ReaderT Int IO Double
qual seria o resultadoask
. Precisamos especificar uma assinatura de tipo como abaixoAlém de ser insensato, não é conveniente especificar o tipo repetidamente.
Como conclusão, usando a definição real de
ReaderT
. Quando você tem algo parecido comval :: ReaderT String IO Int
a dependência funcional, diz: Esse tipo pode ter apenas uma instância única daMonadReader
classe, definida como aquela que usaString
comor
fonte