在this answer中,我在现场制作了一些类似于"更高阶Traversable
":Traversable
的东西,但对于该类别的仿函数Hask to Hask的endofunctors。
{-# LANGUAGE RankNTypes #-}
import Data.Functor.Compose
import Data.Functor.Identity
class HFunctor t where
hmap :: (forall x. f x -> g x) -> t f -> t g
class HFunctor t => HTraversable t where
htraverse :: Applicative g => (forall x. f x -> g x) -> t f -> g (t Identity)
htraverse eta = hsequence . hmap eta
hsequence :: Applicative f => t f -> f (t Identity)
hsequence = htraverse id
我让HFunctor
成为HTraversable
的超类,因为它似乎是正确的,但当我坐下来写hmapDefault
时,我被卡住了。
hmapDefault :: HTraversable t => (forall x. f x -> g x) -> t f -> t g
hmapDefault eta = runIdentity . htraverse (Identity . eta)
-- • Couldn't match type ‘x’ with ‘g x’
-- Expected type: f x -> Identity x
-- Actual type: f x -> Identity (g x)
Identity . eta
的类型为forall y. f y -> Identity (g y)
,因此当我将其传递到htraverse
g
与Identity
结合时,x
必须与y
和g y
都是如此,所以它失败了,因为遍历函数不是自然转换。
我尝试使用Compose
补丁:
hmapDefault :: HTraversable t => (forall x. f x -> g x) -> t f -> t g
hmapDefault eta = runIdentity . getCompose . htraverse (Compose . Identity . eta)
现在Compose . Identity . eta
是一种自然转换,但你不能htraverse
使用它,因为你不知道Applicative g
。即使您可以这样做,runIdentity
来电也会返回g (t Identity)
,而您又无法将g
放回t
。
然后我意识到我的htraverse
与普通的traverse
非常相似。 traverse
的遍历函数将新值置于内Applicative
效果,使类型表达式更大。所以htraverse
应该看起来像这样:
class HFunctor t => HTraversable t where
htraverse :: Applicative a => (forall x. f x -> a (g x)) -> t f -> a (t g)
很有希望这个定义看起来更像Traversable
,hmapDefault
顺便说一句,
hmapDefault :: HTraversable t => (forall x. f x -> g x) -> t f -> t g
hmapDefault eta = runIdentity . htraverse (Identity . eta)
但是我很难为sequenceA
提出一个好的模拟。我试过了
hsequence :: (HTraversable t, Applicative f) => t f -> f (t Identity)
hsequence = htraverse (fmap Identity)
但我无法根据htraverse
提出实施hsequence
的方法。和以前一样,f
不是自然变换。
htraverse f = hsequence . hmap f
-- • Couldn't match type ‘x’ with ‘g x’
-- Expected type: f x -> a x
-- Actual type: f x -> a (g x)
我怀疑我的hsequence
类型签名错误。问题是Applicative
- 我是否需要一直到indexed monads?对于从Functor
类别到Hask"的可遍历仿函数的类应该怎样?看起来像?这样的事情是否存在?
答案 0 :(得分:7)
首先,我们有sequence = traverse id
。
此处htraverse
的第一个参数的类型为forall x. f x -> a (g x)
,我们不能拥有id
,但我们可以尝试使用同构。要使f x
与a (g x)
同构,我们可以选择f ~ Compose a g
。
htraverse = hsequence . hmap (Compose . eta)
hsequence :: Applicative a => t (Compose a g) -> a (t g)
hsequence = htraverse getCompose