Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 是否可以反转类型对齐的遍历?_Haskell_Dependent Type - Fatal编程技术网

Haskell 是否可以反转类型对齐的遍历?

Haskell 是否可以反转类型对齐的遍历?,haskell,dependent-type,Haskell,Dependent Type,这里有很多设置。如果您以前见过类型对齐的序列,您可以将所有内容都略过一行 与类型对齐的序列是任何看起来模糊不清的东西 data ConsList c x y where CNil :: ConsList c x x Cons :: c x y -> ConsList c y z -> ConsList c x z 为Atkey类型的索引函子和应用函子提供了一个类 class IxFunctor f where ixmap :: (a -> b) ->

这里有很多设置。如果您以前见过类型对齐的序列,您可以将所有内容都略过一行

与类型对齐的序列是任何看起来模糊不清的东西

data ConsList c x y where
  CNil :: ConsList c x x     
  Cons :: c x y -> ConsList c y z -> ConsList c x z
为Atkey类型的索引函子和应用函子提供了一个类

class IxFunctor f where
  ixmap :: (a -> b) -> f x y a -> f x y b
class IxFunctor f => IxApply f where
  ixap :: f i j (a -> b) -> f j k a -> f i k b
class IxApply f => IxApplicative f where
  ixpure :: a -> f i i a
和两个索引的McBride样式函子类:

type (f :: q -> r -> *) ~~> (g :: q -> r -> *) =
  forall (i :: q) (j :: r) . f i j -> g i j

class TFunctor t where
  tmap :: (c ~~> d) -> (t c ~~> t d)
可以描述适用于类型对齐序列的映射、折叠和遍历:

class TFoldable t where
  tfoldMap :: Category d => (c ~~> d) -> t c ~~> d
  tfoldMap f = tfoldr (\cij djk -> f cij >>> djk) id

class (TFunctor t, TFoldable t) => TTraversable t where
  ttraverse :: IxApplicative f
            => (forall x y . c x y -> f x y (d x y))
            -> (t c p q -> f p q (t d p q))
现在可以为类型对齐序列定义一个版本的
Data.Functor.Reverse
。具体地

newtype Reverse t c x y = Reverse {unReverse :: t (Dual c) y x}
在哪里

当类型
t
实际上是一个与类型对齐的序列时,可以直接为
反向t
提供与类型对齐的序列操作的完整补充


实际问题 我不清楚的是
t
IxTraversable
是否足以实现
IxTraversable(反向t)
。我所做的一切都是徒劳的。对于标准的
可遍历
s,这可以使用
向后
应用程序来完成。有一个
IxBackwards
可用,但似乎没有帮助。对于标准的
Traversable
s,可以将容器内容转储到列表中,然后从列表中收回。但这在这里似乎是不可能的,因为没有明显的方法来记录输出时的类型,并确保它们在输入时匹配。我错过了什么,还是这是一个禁区

最简单的开始:

instance IxTraversable t => IxTraversable (Reverse t) where
  ttraverse f (Reverse xs) = Reverse `ixmap` _ xs
这让我有一个洞的类型

t (Dual c) q p -> f p q (t (Dual d) q p)
明显的挑战是我们有
t\uqp
,但是
f p\uq
。因此,如果有办法做到这一点,我们可能需要以某种方式想出一个f,它将翻转事物。正如我之前所说的,有一个
IX向后

newtype IxBackwards f y x a = IxBackwards { ixforwards :: f x y a }

但我看不出这有什么帮助。

您的设置是合理的,
IxBackwards
是有用的(事实上,非常关键)-您遇到的问题是,类型变量的
反向
交换位置,而
ttraverse
的第一个参数要求量化类型变量(
x,y
)的位置在某种意义上“一致”。在对
ttraverse
的递归调用中,您必须同时使用
Dual
IxBackwards
来“翻转”这些变量:

instance TTraversable t => TTraversable (Reverse t) where

  ttraverse f = 
    ixmap Reverse . ixforwards . 
    ttraverse (IxBackwards . ixmap Dual . f . getDual) . 
    unReverse 
编写
TFunctor
TFoldable
的实例可能会提示如何找到此实现:

dualNat2 :: (c ~~> d) -> Dual c ~~> Dual d 
dualNat2 k (Dual x) = Dual $ k x 

instance TFunctor f => TFunctor (Reverse f) where 
  tmap f (Reverse q) = Reverse $ tmap (dualNat2 f) q 

instance TFoldable f => TFoldable (Reverse f) where 
  tfoldMap k (Reverse z) = getDual $ tfoldMap (dualNat2 k) z 
TTraversable
的情况下基本上也是这样,只是现在有两个索引需要翻转:

f                                      :: forall x y . c x y -> f x y (d x y)   
ixmap Dual . f . getDual               :: forall x y . Dual c y x -> f x y (Dual d y x)
IxBackwards . f                        :: forall x y . c x y -> IxBackwards f y x (d x y)
IxBackwards . ixmap Dual . f . getDual :: forall x y . Dual c y x -> IxBackwards f y x (Dual d y x)
请注意,如果只翻转其中一个索引,函数的类型甚至与
ttraverse
的参数类型不匹配


我将尝试使用键入的孔进行逐步推导

从这个骨架开始,我认为这是一个微不足道的推导:

  ttraverse f = 
    ixmap Reverse .  
    ttraverse _trfun . 
    unReverse 
这会产生一个类型错误:

Couldn't match type `q' with `p'
...
Expected type: Reverse t c p q -> f p q (Reverse t d p q)
Actual type: Reverse t c q p -> f p q (Reverse t d q p)
* In the expression: ixmap Reverse . ttraverse _trfun . unReverse
因此,在编译之前,添加更多的孔。我的第一反应是在前面再加一个孔(因为类型错误是针对整个表达式的,所以必须对整个表达式进行某些操作才能进行类型检查):

现在我们没有得到类型错误(忽略
cx
形式的“不明确类型”错误,其中
C
是一个类-存在错误),并且报告的类型是

 _out :: f0 q p (Reverse t c0 p q) -> f p q (Reverse t d p q)
其中,
f0,c0
是(当前)自由类型变量,我们使用它来发挥优势!如果我们让
c0~d
f0~ixforwards f
,那么这正是
ixforwards
的类型-那么让我们试试它:

  ttraverse f = 
    ixforwards . ixmap Reverse .  
    ttraverse _trfun . 
    unReverse 
现在我们得到了一个很好的单态推断类型:

 _trfun :: Dual c x y -> IxBackwards f x y (Dual d x y)
 * Relevant bindings include
     f :: forall (x :: r) (y :: r). c x y -> f x y (d x y)
_out :: f y x (d y x) -> IxBackwards f x y (Dual d x y)
现在我还假设很明显,
\u trfun
应该以某种方式使用
f
,所以让我们试试看。我们注意到,
f
的域和范围与
\u trfun
的域和范围并不完全相同,因此我们在两侧放置了一个孔:

  ttraverse f = 
    ixforwards . ixmap Reverse .  
    ttraverse (_out . f . _in) . 
    unReverse 
并获得:

_out :: f x0 y0 (d x0 y0) -> IxBackwards f x y (Dual d x y)
_in :: Dual c x y -> c x0 y0
_out :: IxBackwards f x y (d y x) -> IxBackwards f x y (Dual d x y)
其中,
x0,y0
是自由变量。最明显的可能是,对于
x0~y,y0~x
,我们在=getDual
中有
\u,所以我们尝试了一下,得到了一个新的推断类型:

 _trfun :: Dual c x y -> IxBackwards f x y (Dual d x y)
 * Relevant bindings include
     f :: forall (x :: r) (y :: r). c x y -> f x y (d x y)
_out :: f y x (d y x) -> IxBackwards f x y (Dual d x y)
现在很明显,类型变量在两个不同的地方“翻转”;一次通过
IX向后
和一次通过
Dual
。翻转第一对索引的方法最明显(可能):

并获得:

_out :: f x0 y0 (d x0 y0) -> IxBackwards f x y (Dual d x y)
_in :: Dual c x y -> c x0 y0
_out :: IxBackwards f x y (d y x) -> IxBackwards f x y (Dual d x y)
现在我们有了形式为
qa->qb
IxFunctor q
,所以设置
\u out=ixmap\u out
我们得到

_out :: d y x -> Dual d x y
这类函数中有一个简单的函数,即
Dual
,它完成了定义:

  ttraverse f = 
    ixforwards . ixmap Reverse .  
    ttraverse (ixmap Dual . IxBackwards . f . getDual) . 
    unReverse 

请注意,与原始版本相比,有些函数组合是如何翻转的——我假装我事先不知道答案,并通过先填写最简单的内容,以“最明显”的方式推导出来。这两个定义是等价的(真正等价的,因为
Dual
IxBackwards
都是
newtype
s)

啊!在我的努力中,我真的很接近那个答案,但从未达到那个程度。你能解释一下你是怎么计算出来的吗?或者如何计算呢?我添加了一个详细的推导,希望能有一些意义。它仍然需要在你的头脑中做一些打字检查,但是打字孔使这变得容易一些。