2014-12-22 107 views
2

我目前正試圖重載MonadTrans以前的提取函數。我現在的嘗試是把內,單子m爲關聯型Result的實例:Haskell中的變量關聯類型/數據類型

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) 
    type Result = m -- This is there the error is thrown 
    runFooReader = runReaderT 

爲什麼Foo的形狀滑稽的唯一原因是由於MonadTransMonadReader限制。基本上,這是強制所有關聯的類型實例是單形類型(正確?)。

我當時以爲要重新設計,使Result只需一個多態vairable:

... 
class FooReader prefix m where 
    runFooReader :: forall b result. m b -> prefix -> result b 

...但隨後的情況下,各類resultw(如果它是ReaderT prefix wm,例如) 不會統一。有沒有什麼辦法可以使varialbe/idea變種多變但可判定?

+1

嘗試'類FooReader前綴M |前綴 - > m',這就是'mtl'和類似的東西(它可能是你想要的)。如果我理解正確,你想編寫一個函數「run」,它需要一個任意的「monad變換器棧」和「解開」它,本質上就像runStateT,runReaderT,runReaderT。 runStateT'等,具體取決於類型。我記得寫了一些代碼,它做到了這一點 - 它的工作,但類型錯誤是可怕的,總體上比它的價值更多的努力 - 所以只是堅持定義函數爲您經常遇到的特定類型。 – user2407038

回答

4

清理語法錯誤,並添加了一種註解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 
+0

我的歉意,'MonadTrans'超類是一個錯誤,然而這正是我需要的。真心謝謝:) –