什么应该更高的顺序可穿越"上课看起来像?

时间:2017-05-25 18:59:39

标签: haskell functional-programming monads category-theory traversable

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 gIdentity结合时,x必须与yg 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)

很有希望这个定义看起来更像TraversablehmapDefault顺便说一句,

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"的可遍历仿函数的类应该怎样?看起来像?这样的事情是否存在?

1 个答案:

答案 0 :(得分:7)

首先,我们有sequence = traverse id

此处htraverse的第一个参数的类型为forall x. f x -> a (g x),我们不能拥有id,但我们可以尝试使用同构。要使f xa (g x)同构,我们可以选择f ~ Compose a g

htraverse = hsequence . hmap (Compose . eta)

hsequence :: Applicative a => t (Compose a g) -> a (t g)
hsequence = htraverse getCompose