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)