Haskell 斯科蒂的蒙纳恐怖分子的例子';s行动

Haskell 斯科蒂的蒙纳恐怖分子的例子';s行动,haskell,scotty,Haskell,Scotty,我有这个型号 ActionT TL.Text (ReaderT T.Text IO) 我正试着为这个做一个更可怕的例子,这样我就不必提要求,但总是能得到 (All instance types must be of the form (T a1 ... an) where a1 ... an are *distinct type variables*, and each type variable appears at most once in the instance head.

我有这个型号

ActionT TL.Text (ReaderT T.Text IO)
我正试着为这个做一个更可怕的例子,这样我就不必提要求,但总是能得到

 (All instance types must be of the form (T a1 ... an)
  where a1 ... an are *distinct type variables*,
  and each type variable appears at most once in the instance head.
  Use -XFlexibleInstances if you want to disable this)
我已经尝试了很多实例类型,下面有几个,但它们总是出现上面的错误

instance MonadReader T.Text (ActionT TL.Text (ReaderT T.Text IO))    

instance MonadReader r (ActionT TL.Text (ReaderT r IO))

instance (ScottyError e, MonadReader r m) => MonadReader r (ActionT e (ReaderT r m))
我觉得我在实例中遗漏了一些基本的东西。我想我理解FlexibleInstances,但我看不出这在这里是如何应用的

如果您对实例类型有任何帮助,我将不胜感激。我希望自己实现
ask
local
,因为我的主要目标是学习

谢谢

更新 我使用了
FlexibleInstances、multiparamtypeClass、undedicatableInstances

instance  (ScottyError e, Monad m, MonadReader r m) => MonadReader r (ActionT e m) where
  ask = lift ask

仍在致力于实施本地技术。我还假设
不可判定的实例
是坏的

更新2 我想我真正需要的是

instance  (ScottyError e, Monad m, MonadReader r m) => MonadReader r (ActionT e (ReaderT r m)) where

但是我仍然无法理解
local

正如您自己回答的那样,您需要
不可判定实例
来实现完全通用的
monawarder
实例。这是一个必要的缺点,您可以在实现此类泛型monad类型类实例的所有库中看到它

我担心实现
local
将是一个问题。如果你看一下,它们都使用某种特定于特定单子的映射函数。而且,由于似乎没有一个
ActiveT
导出这样的方法或其内部结构,因此它看起来不可行

instance  (ScottyError e, Monad m, MonadReader r m) => MonadReader r (ActionT e (ReaderT r m)) where
但是,Scotty没有公开实现本地功能所需的函数

我正在尝试编写一个
mapActionT
来实现
local
,如果我找到了执行该操作的类型,我将更新此答案:)

编辑:

我想我有地图,但我不确定

mapActionT :: (Monad m, Functor n, ScottyError e) => (forall a . m a -> n a) -> ActionT e m b -> ActionT e n b
mapActionT nat m = ActionT $ flip mapErrorT (runAM m) $ \rt -> 
        flip mapReaderT rt $ \st ->
            StateT $ \s -> fmap (\a -> (a,s)) (nat (evalStateT st s))
我最终从起重机上复制了类型签名,这样我就可以为我的fmap引入函子n


欢迎对实施提出任何意见。

我建议您将问题部分的答案改为正确答案。回答你自己的问题是很好的,甚至是。
不可判定的实例
其实也没有什么问题。它允许您定义理论上可能循环类型检查器的实例,但类型检查器有一个内置的递归限制,使其在编译时失败。只有当您确切地知道它们是如何工作的,以及为什么它们不是标准的一部分时,才需要启用
重叠实例
不一致性
<代码>不可判定的实例相比之下是无害的。谢谢你的解释,这对我来说是全新的。谢谢,我也得出了这个结论。我已经分叉了存储库,并打算为ActionT添加一个Monawarder实例。然而,我也注意到了mapT函数,我想知道实现它是否会更好,尽管也没有什么能阻止我同时做这两件事。@IvanMeredith我赞成实现类似
mapActionT::(MA->NA)->ActionT MA->ActionT n a
。由于
ActionT
在内部只是一个monad转换器的组合,这应该很容易,只需组合相应的
map..
函数即可。这可以用于许多其他目的——在许多情况下,更改内部单子很方便。例如
mapActionT liftIO::(MonadIO m)=>ActionT IO a->ActionT m a
。它还允许您非常轻松地实现
Monawarder
实例。@IvanMeredith此外,
mapActionT
允许您轻松地从mmorph包实现(就像
葫芦f=mapActionT f
),它为您提供了一个非常通用的界面。@PatrPudlak对,我已经想出了这个类型签名,但是在用mapStateT实现堆栈的
(ma->na)->StateT->StateT
部分时却步履维艰。不过,我会看看起重机。我以前在scalaz看过,我认为
MA->NA
很熟悉,但不记得从哪里来的。