2015-11-06 3 views
4

Я пытаюсь выяснить, как реализовать экземпляр MonadBaseControl для типа Foo, который является оболочкой newtype вокруг экземпляра StateT. Вы думаете, что это будет реализовано точно так же, как this, но это, похоже, не так. Я предполагаю, что часть штата вызывает проблему здесь, так есть способ ее сбросить?MonadBaseControl IO ... StateT Реализация

Код:

newtype Foo a = Foo { unFoo :: StateT Int IO a } 
       deriving (Monad, Applicative, Functor, MonadBase IO) 

instance MonadBaseControl IO Foo where 
    type StM Foo a = a 
    liftBaseWith f = Foo $ liftBaseWith $ \q -> f (q . unFoo) 
    restoreM = Foo . restoreM 

Ошибка:

Couldn't match type ‘a’ with ‘(a, Int)’ 
‘a’ is a rigid type variable bound by 
the type signature for restoreM :: StM Foo a -> Foo a 
    Expected type: a -> StateT Int IO a 
Actual type: StM (StateT Int IO) a -> StateT Int IO a 
Relevant bindings include 
restoreM :: StM Foo a -> Foo a 
In the second argument of ‘(.)’, namely ‘restoreM’ 
    In the expression: Foo . restoreM 

ответ

8

Чтобы избежать UndecidableInstances, связанный ответ расширил семейство типа, что для человека читаемости, это действительно не должно иметь. А именно, он пишет

instance MonadBaseControl IO Foo where 
    type StM Foo a = a 

, когда вместо того, чтобы можно было бы рассмотреть вопрос о написании

instance MonadBaseControl IO Foo where 
    type StM Foo a = StM (ReaderT Int IO) a 

, чтобы сделать его более ясным, как выбрать правильную правую для данных ньютайпов упаковки. С аналогичным изменением (и UndecidableInstances) ваш код работает нормально. Если вы хотите избежать UndecidableInstances, вы можете сделать то же расширение, что и в связанном ответе; пример того, чтобы просить GHCi, что расширение должно быть выглядит следующим образом:

> :kind! forall a. StM (StateT Int IO) a 
forall a. StM (StateT Int IO) a :: * 
= (a, Int) 

Так что для версии FooStateT мы могли бы также написать:

instance MonadBaseControl IO Foo where 
    type StM Foo a = (a, Int) 
+0

Ницца, это сработало. Благодаря! Из любопытства, как мне написать версию вида, чтобы мне не нужны «UndecidableInstances»? – Josh

+0

@Josh Что вы подразумеваете под «версией видов»? –

+0

Woops извините, полагаю, я сформулировал это неправильно? По существу, как использовать «forall a. StM (StateT Int IO) a», чтобы избежать «UndecidableInstances». – Josh