是否有可能在结构演算中表达平衡的未标记二叉树的类型?

时间:2015-10-25 14:41:36

标签: haskell functional-programming dependent-type morte

我正试图通过项目Morte来探索和理解构造计算的领域。我知道可以在Agda中表示这样的数据类型,但是对于我来说如何在这样的极简主义环境中表示它并不明显。怎么可能这样呢?我的意思是这个数据类型,在Idris中:

data Tree : Nat -> Type -> Type where
    Leaf : a -> Tree Z a
    (::) : Tree k a -> Tree k a -> Tree (S k) a

2 个答案:

答案 0 :(得分:5)

我不知道Morte的细节,但我有一些线索可以更广泛地了解类型lambda-calculi的可能性。

如果Nat被无法定义,则可以通过迭代定义这些树。

Nat : *
Nat = (x : *) -> (x -> x) -> x -> x
Pair : * -> * -> *
Pair x y = (z : *) -> (x -> y -> z) -> z
Tree : * -> Nat -> *
Tree a n = n * (\ t -> Pair t t) a

当然,为了逃避这一点,我需要消除。在这里,我随便采取* : *,但这一般不安全。归纳定义可以毫无疑问地允许大量消除:不可预测编码的数据类型,不是这样。

但是,上面,我利用了这样一个事实,即树的索引结构恰好与索引它们的Nat的索引结构兼容,并且没有理由说这一般情况应该如此。指数各种各样古怪的方式各不相同:它只是那些表征某种“大小”的方式。随着我们向内走,它会变小。

索引结构确实允许教会编码演示。它不是迭代一个集合,而是迭代一个索引集。这是表达它的一种方式。

Tree : * -> Nat -> *
Tree a n = (x : Nat -> *) ->
           (a -> x Z) ->
           ((n : Nat) -> x n -> x n -> x (S n)) ->
           x n

写一些像

这样的东西很容易
leftmost : (a : *) -> (n : Nat) -> Tree a n -> a
leftmost a n t = t (\ _ -> a) (\ a -> a) (\ _ l _ -> l)

leftChild : (a : *) -> (n : Nat) -> Tree a (S n) -> Tree a n

是一个更高的订单,需要一些方法来检查或约束数字。这就是为什么GHC Haskell拥有关于平等的所有这些东西,~

答案 1 :(得分:3)

我所看到的Morte,一切都是使用Church编码编码的。例如。列出您链接的帖子的示例:

data List a = Cons a (List a) | Nil

编码为

type List a = forall x . (a -> x -> x) -> x -> x

依赖类型的第一个例子是长度索引列表又名矢量:

data Vec a (n :: Nat) where
  VNil :: forall a. Vec a 0
  VCons :: forall a (n :: Nat). a -> Vec n a -> Vec (S n) a

这种野兽的教会编码是什么?我不知道哪种思维启发式对您有用, 你必须亲自发现它。

我的思维方式:Vector与list非常不同。它更像是n-ary homogeous 元组。几个例子编码:

type Singleton a  = forall x. (a -> x) -> x            -- Vec a 1
type Pair a       = forall x. (a -> a -> x) -> x       -- Vec a 2
type Triple a     = forall x. (a -> a -> a -> x) -> x  -- Vec a 3

模式很明显。我们需要的是从自然数到类型族的函数:

nTupleType a 0 x  = x
nTupleType a 1 x  = a -> x         = a -> nTupleType a 0 x
nTupleType a 2 x  = a -> (a -> x)  = a -> nTupleType a 1 x
nTupleType a n x  = ... -- General equation is left as an exercise

鉴于此,我们可以编码Vec

type Vec a n = forall x. nTupleType a n x -> x

vnil = \x -> x
vcons (a : *) (n : Nat) (h : a) (t : Vec a n) = \x f -> t x (f h) -- I'm not sure if I got this right

使用类似的方法,您可以编码其他索引数据结构。对于原始问题:完全平衡的树,编码看起来非常相似,nTupleType必须从线性变为指数(0,1,2,3, ...)(1, 2, 4, 8, ...)

值得注意的是,树的实际形状将隐藏在Morte中:Tree a n ~ Vec a (exp2 n)。 OTOH是Morte的观点。我想。