【问题标题】:Idris vectors vs linked listsIdris 向量与链表
【发布时间】:2015-02-17 12:46:46
【问题描述】:

Idris 是否在向量引擎下进行了任何类型的优化?因为从外观上看,Idris 向量只是一个已知大小(在编译时已知)的链表。事实上,一般来说,您似乎可以表达以下等价(我在语法上猜测了一下):

Vector : Nat -> Type -> Type
Vector n t = (l: List t ** length l = n)

因此,虽然这在防止范围错误方面很好,但向量的真正优势(在该术语的传统用法中)是在性能方面;特别是 O(1) 随机访问。 idris 向量似乎不支持这一点(您将如何编写索引函数来获得这种性能?)。

  • 假设内部没有魔法(就像 Nat 那样)重新配置 Vectors,Idris 中是否存在随机访问数据类型?
  • 如何在代数类型系统中定义这样的东西?当然,似乎无法归纳地定义它。
  • 是否有可能在像 Idris 这样的类型系统中创建支持 O(1) 随机访问的数据类型,并且知道它的长度,以便所有访问都可以证明是有效的? (Haskell 有数组样式的向量,但它们的具体实现对普通用户来说是不透明的,包括我在内)

【问题讨论】:

    标签: vector linked-list algebraic-data-types idris


    【解决方案1】:

    它对优化向量查找没有任何作用(至少在撰写此答案时)。

    这并不是因为这样做有任何困难,真的,而是因为我宁愿有某种通用框架来编写这种优化,而不是对它们进行硬编码。诚然,我们已经对 Nat 进行了硬编码优化,但我仍然不希望以临时方式添加更多负载。

    根据您的实际需要,实验性的唯一性类型系统可能会有所帮助,因为您可以在底层拥有一个低级别的可变事物,并且仍然可以安全高效地访问和更新纯粹的风格在高级语言中。我们拭目以待……

    【讨论】:

      【解决方案2】:

      Edwin has the definitive answers on what Idris currently does. 但是,如果您正在寻找在某些情况下可能很自然地优化为恒定时间查找的东西,那么以下可能是朝着正确方向迈出的一步。

      对于编译时固定大小的向量(即,不在 lambda 下,不在顶层由长度参数化),以下结构为您提供向量和查找函数,对于任何固定的具体长度,都可以编译 -时间归一化为应该可以直接优化为常数时间函数的函数。 (抱歉,代码在 Coq 中;我目前没有 Idris 的工作版本,也不太了解。如果有人建议正确的语法,我很乐意用 Idris 代码替换它,例如,在评论。)

      Fixpoint vector (n : nat) (A : Type) :=
        match n return Type with
          | 0 => unit
          | S n' => (A * vector n' A)%type
        end.
      Definition nil {A} : vector 0 A := tt.
      Definition cons {n} {A : Prop} (x : A) (xs : vector n A) : vector (S n) A
        := (x, xs).
      Fixpoint get {n} {A : Prop} (m : nat) (default : A) (v : vector n A) {struct n} : A
        := match n as n return vector n A -> A with
             | 0 => fun _ => default
             | S n' => match m with
                         | 0 => fun v => fst v
                         | S m' => fun v => @get n' A m' default (snd v)
                       end
           end v.
      

      这个想法是,对于任何固定的 nget 的正常形式是非递归的,因此编译器可以假设将其编译成一个运行时独立于什么的函数n 恰好是。

      【讨论】:

      • 最初的问题是关于访问 O(1) 中的元素。显然,如果你修复了n,那么访问将是恒定的时间。
      • 我已经编辑了最后一句话,以使以下几点更清楚,我希望:关键是 n 必须固定为一个值,无论它在哪里使用。它应该是 O(1) 作为您在编译时修复 n 的值的函数。也就是说,在 Idris 可以将 A * B * ... * C 编译成数组的假设世界中,插入 n = 5 时的绝对运行时间应该与插入 n = 100000,但前提是你在编译时这样做。