清理語法錯誤,並添加了一種註解Result
,我們得到這樣的:
class (Monad Result
, MonadTrans m
, MonadReader prefix m
) => FooReader prefix m where
type Result :: * -> *
runFooReader :: forall b. m b -> prefix -> Result b
instance Monad m => FooReader prefix (ReaderT prefix m) where
type Result = m -- Again, error triggered here
runFooReader = runReaderT
和更有趣的錯誤:
The RHS of an associated type declaration mentions type variable `m'
All such variables must be bound on the LHS
這在the GHC docs擴展:
The visibility of class parameters in the right-hand side of associated family instances depends solely on the parameters of the family. As an example, consider the simple class declaration
class C a b where
data T a
Only one of the two class parameters is a parameter to the data family. Hence, the following instance declaration is invalid:
instance C [c] d where
data T [c] = MkT (c, d) -- WRONG!! 'd' is not in scope
Here, the right-hand side of the data instance mentions the type variable d that does not occur in its left-hand side. We cannot admit such data instances as they would compromise type safety.
探索「它會危及類型安全」po詮釋,想象這GHCi會議:
> :kind! Result
Result :: * -> *
= {- ... well, what? m? -}
你可能是指type Result prefix (ReaderT prefix m) = m
。
仍然有錯誤。值得注意的是,那種m
是不一致的; MonadTrans
需要種類參數(* -> *) -> * -> *
,而MonadReader
的第二個參數需要* -> *
。我不明白你爲什麼需要MonadTrans
。
我不明白你的意思是「強制所有關聯的類型實例是單形類型」;你寫的Result
類型不是一個真正的類型函數,因爲它沒有任何參數; LHS上沒有任何類型變量。
這裏的東西,編譯:
class (Monad (Result m)
, MonadReader prefix m
) => FooReader prefix (m :: * -> *) where
type Result m :: * -> *
runFooReader :: forall b. m b -> prefix -> Result m b
instance Monad m => FooReader prefix (ReaderT prefix m) where
type Result (ReaderT prefix m) = m
runFooReader = runReaderT
> :kind! Result (ReaderT Int IO)
Result (ReaderT Int IO) :: * -> *
= IO
嘗試'類FooReader前綴M |前綴 - > m',這就是'mtl'和類似的東西(它可能是你想要的)。如果我理解正確,你想編寫一個函數「run」,它需要一個任意的「monad變換器棧」和「解開」它,本質上就像runStateT,runReaderT,runReaderT。 runStateT'等,具體取決於類型。我記得寫了一些代碼,它做到了這一點 - 它的工作,但類型錯誤是可怕的,總體上比它的價值更多的努力 - 所以只是堅持定義函數爲您經常遇到的特定類型。 – user2407038