Haskell 有可能实现这种通用翻转吗?

Haskell 有可能实现这种通用翻转吗?,haskell,monads,reader-monad,Haskell,Monads,Reader Monad,我想写一个具有类型签名的对象: genericFlip :: ( MonadReader (o (n c)) m , MonadReader a n , MonadReader b o ) => m (n (o c)) 对于monad阅读器来说,这本质上是一个翻转 现在很容易编写如下所示的版本: genericFlip :: ( MonadReader (b -> a -> c) m , MonadReader a n , MonadRea

我想写一个具有类型签名的对象:

genericFlip ::
  ( MonadReader (o (n c)) m
  , MonadReader a n
  , MonadReader b o
  )
    => m (n (o c))
对于monad阅读器来说,这本质上是一个翻转

现在很容易编写如下所示的版本:

genericFlip ::
  ( MonadReader (b -> a -> c) m
  , MonadReader a n
  , MonadReader b o
  )
    => m (n (o c))
  genericFlip = do
    f <- ask
    return $ do
      a <- ask
      return $ do
        b <- ask
        return $ f b a
genericFlip::
(单子恐惧者(b->a->c)m
蒙纳
,莫纳特b o
)
=>m(n(o c))
genericFlip=do
不,这是不可能的


第一个签名并不能使o可遍历。

仅仅依靠
monawarder
是不行的,但是使用
可遍历
可以得到:

genericFlip::(可遍历的o,单子恐惧者(o(nc))m,单子n)=>m(n(oc))
genericFlip=do

首先,我建议不要将
m
概括为
monawarder
。在
翻转的类型中

flip :: (a -> b -> c) -> (b -> a -> c)
。。。中间的箭头与其他箭头不同:它仅链接翻转的输入和输出。通过这种简化,我们最终为您建议的
genericFlip
提供了一种更简单的类型:

genericFlip :: (MonadReader a n, MonadReader b o) => o (n c) -> n (o c)
在任何情况下,
genericFlip
都不能使用此签名实现。就其本身而言,
monawarder
接口不提供为计算提供环境的方法,这对于交换层是必要的。例如,从你的问题中考虑特殊的<代码>通用翻转<代码>:

genericFlip' :: (MonadReader a n, MonadReader b o) => (b -> a -> c) -> n (o c)
genericFlip' f = do
  a <- ask
  return $ do
    b <- ask
    return $ f b a
我们对flip的一个概括是:

distribute((>)\uu)
也称为or,而
distribute((>)\uu((>)
本身就是
flip

然而,
Distributive
,并没有像我们在这个问题中所希望的那样,将我们从函数中解放出来。对于某些特定的
r
,每个分配函子同构于
(>)r
。当我们看到
可表示的
类时,这种联系变得更加明显,它在原则上等同于
分布式
,但使用了更复杂的编码,使得同构显式化。除了
distribute
flip
的推广外,我们还将
索引
作为函数应用程序模拟,以及
表格
,它看起来非常像
阅读器
。事实上,该类提供了可以通过


最后一点,尽管不完全符合我们提出的广义翻转签名,但非常容易翻转的是
ReaderT r(ReaderT s m)a
,它可以归结为
r->s->ma
。这可能并不完全有用,但是,在实践中,人们通常会将环境组合成一种类型,只使用一个读卡器层,而不是使用嵌套的读卡器层(另请参见)。

如果我们沿着这条路线走,要求
分布式的
而不是
可遍历的
——类似于函数的东西往往是前者而不是后者。“第一个签名没有任何东西使
o
可遍历”——或者
n
分布式。
genericFlip' :: (MonadReader a n, MonadReader b o) => (b -> a -> c) -> n (o c)
genericFlip' = fmap reader . reader . flip
distribute :: (Distributive g, Functor f) => f (g a) -> g (f a)