我想写一个具有类型签名的对象:
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
甚至用(->)
代替Reader
,但是不管我怎么动脑筋,我似乎都无法做出一个适合所有读者的定义。
是否可以在Haskell中制作一个具有这种类型签名的对象?
答案 0 :(得分:1)
首先,我建议不要将m
概括为MonadReader
。以flip
...
flip :: (a -> b -> c) -> (b -> a -> c)
...中间的箭头与其他箭头不同:它仅将翻转的输入和输出链接在一起。通过这种简化,我们最终为您建议的genericFlip
提供了一个简单的类型:
genericFlip :: (MonadReader a n, MonadReader b o) => o (n c) -> n (o c)
在任何情况下,都无法使用此签名来实现genericFlip
。 MonadReader
接口本身无法提供一种为计算提供环境的方法,这对于交换层是必不可少的。例如,考虑以下问题中的专门genericFlip
:
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
从根本上说,它依赖于f
是一个函数,这意味着我们可以为其提供环境(并且,正如您所注意到的,如果我们使用Reader
,我们可以通过{{1 }}。最终,runReader
所做的一切都是将函数转变为阅读器计算,这种无点拼写使它变得透明:
MonadReader
对genericFlip' :: (MonadReader a n, MonadReader b o) => (b -> a -> c) -> n (o c)
genericFlip' = fmap reader . reader . flip
的一种概括是distribute
:
flip
distribute :: (Distributive g, Functor f) => f (g a) -> g (f a)
也称为flap
或(??)
,而distribute @((->) _)
本身就是distribute @((->) _) @((->) _)
。
flip
并没有像我们在此问题中希望的那样使我们脱离函数。对于某些特定的Distributive
,每个分布函子与(->) r
同构。当我们查看r
类时,这些连接变得更加明显,该类在原则上等效于Representable
,但是使用更复杂的编码,使同构显式。除了Distributive
是distribute
的泛化之外,我们还有flip
作为函数应用程序类似物,还有index
,看起来很像tabulate
。实际上,该类提供了a default MonadReader
implementation,可以方便地通过the Co
newtype派生该类。
最后一点,reader
尽管不能完全适合我们建议的通用翻转签名,但仍然非常容易翻转,可以归结为ReaderT r (ReaderT s m) a
。可以说,这并不是那么有用,但实际上,通常不是将嵌套的阅读器布局嵌套在一起,而是将环境组合成一个单一的类型,并只有一个阅读器层(另请参见the RIO
monad)。
答案 1 :(得分:0)
不。这是不可能的。
第一个使o可以遍历的签名没有什么。
答案 2 :(得分:0)
仅依靠MonadReader
就可以,但是Traversable
可以使您得到:
genericFlip :: (Traversable o, MonadReader (o (n c)) m, Monad n) => m (n (o c))
genericFlip = do
onc <- ask
return $ sequence onc
添加其他MonadReader
约束不会有任何危害,但是我无法确切地看到您要使用这些monad或其环境实现的目标。
genericFlip ::
(Traversable o, MonadReader (o (n c)) m, MonadReader a n, MonadReader b o) => m (n (o c))
genericFlip = asks sequence
一个例子可能会有所帮助。