简体   繁体   English

idris中的排序列表(插入排序)

[英]Sorted list in idris (insertion sort)

I am writing an undergraduate thesis on usefulness of dependent types. 我正在撰写关于依赖类型有用性的本科论文。 I am trying to construct a container, that can only be constructed into a sorted list, so that it is proven sorted by construction: 我正在尝试构造一个容器,只能构造成一个排序列表,以便它被证明按构造排序:

import Data.So

mutual
  data SortedList : (a : Type) -> {ord : Ord a) -> Type where
    SNil : SortedList a
    SMore : (ord : Ord a) => (el: a) -> (xs : SortedList a) -> So (canPrepend el xs) -> SortedList a

  canPrepend : Ord a => a -> SortedList a -> Bool
  canPrepend el SNil = True
  canPrepend el (SMore x xs prf) = el <= x

SMore requires a runtime proof that the element being prepended is smaller or equal than the smallest (first) element in the sorted list. SMore需要运行时证明,前置元素小于或等于排序列表中的最小(第一)元素。

To sort an unsorted list, I have created a function sinsert that takes a sorted list and inserts an element and returns a sorted list: 为了排序未排序的列表,我创建了一个函数sinsert ,它接受一个排序列表并插入一个元素并返回一个排序列表:

sinsert : (ord : Ord a) => SortedList a {ord} -> a -> SortedList a {ord}
sinsert SNil el = SMore el SNil Oh
sinsert (SMore x xs prf) el = either 
  (\p => 
    -- if el <= x we can prepend it directly
    SMore el (SMore x xs prf) p
  ) 
  (\np =>  
    -- if not (el <= x) then we have to insert it in the tail somewhere
    -- does not (el <= x) imply el > x ???

    -- we construct a new tail by inserting el into xs
    let (SMore nx nxs nprf) = (sinsert xs el) in
    -- we get two cases:
    -- 1) el was prepended to xs and is now the 
    --    smalest element in the new tail
    --    we know that el == nx
    --    therefor we can substitute el with nx
    --    and we get nx > x and this also means 
    --    x < nx and also x <= nx and we can
    --    prepend x to the new tail
    -- 2) el was inserted somewhere deeper in the
    --    tail. The first element of the new tail
    --    nx is the same as it was in the original
    --    tail, therefor we can prepend x to the
    --    new tail based on the old proof `prf`
    either 
      (\pp => 
        SMore x (SMore nx nxs nprf) ?iins21
      )
      (\npp => 
        SMore x (SMore nx nxs nprf) ?iins22
      ) (choose (el == nx))
  ) (choose (el <= x))

I am having trouble constructing the proofs ( ?iins21 , ?iins22 ) and I would appreciate some help. 我在构建样张时遇到了麻烦( ?iins21?iins22 ),我将不胜感激。 I may be relying on an assumption that does not hold, but I do not see it. 我可能依赖于一个不成立的假设,但我没有看到它。

I would also like to encourage you to provide a better solution for constructing a sorted list (maybe a normal list with a proof value that it is sorted?) 我还想鼓励你为构建一个排序列表提供一个更好的解决方案(也许是一个带有证明值的普通列表,它被排序?)

I think that the main problem with your proofs there is that, as Cactus noted in a comment, is that you don't have properties like transitivity and antisymmetry that are needed for the proof of insertion sort to work. 我认为你的证据存在的主要问题是,正如Cactus在评论中指出的那样,你没有像传递性和反对称性这样的属性,这些属性是插入排序证明工作所必需的。 However, you can still make a polymorphic container: the Poset class from Decidable.Order in contrib contains exactly the properties that you want. 但是,您仍然可以创建一个多态容器:contrib中的Decidable.Order中的Poset类包含您想要的属性。 However, Decidable.Order.Order is better in this case since it encapsulates the totality of the relation, ensuring that for any two elements we can get a proof that one of them is smaller. 但是,Decidable.Order.Order在这种情况下更好,因为它封装了关系的整体,确保对于任何两个元素我们可以得到一个证明其中一个更小的证明。

I have another insertion sort algorithm that I was working on anyway that uses Order; 我有另一个插入排序算法,我正在使用Order, it also explicitly decomposes the distintion between Empty and NonEmpty lists and keeps the max (the largest element that can now be added to the list) value in the type of NonEmpty lists, which simplifies proofs somewhat. 它也明确分解之间的distintion EmptyNonEmpty列表并保持max的类型值(即现在可以添加到列表中的最大元素) NonEmpty单,这在一定程度简化了证明。

I am also in the process of learning Idris, so this code may not be the most idiomatic; 我也在学习伊德里斯,所以这段代码可能不是最惯用的; also, many thanks to Melvar and {AS} on the #idris Freenode IRC channel for helping me figure out why previous versions didn't work. 此外,非常感谢Melvar和{AS}在#idris Freenode IRC频道上帮助我弄清楚为什么以前的版本不起作用。

The weird with (y) | <pattern matches on y> 奇怪的with (y) | <pattern matches on y> with (y) | <pattern matches on y> syntax in sinsert is there in order to bind y for assert_smaller , since, for some reason, y@(NonEmpty xs) does not work. with (y) | <pattern matches on y> sinsert语法是为了绑定yassert_smaller ,因为由于某种原因, y@(NonEmpty xs)不起作用。

I hope this is helpful! 我希望这是有帮助的!

import Data.So
import Decidable.Order

%default total

data NonEmptySortedList :  (a : Type)
                        -> (po : a -> a -> Type)
                        -> (max : a)
                        -> Type where
  SOne   : (el : a) -> NonEmptySortedList a po el
  SMany  :  (el : a)
         -> po el max
         -> NonEmptySortedList a po max
         -> NonEmptySortedList a po el

data SortedList : (a : Type) -> (po : a -> a -> Type) -> Type where
  Empty : SortedList _ _
  NonEmpty : NonEmptySortedList a po _ -> SortedList a po

head : NonEmptySortedList a _ _ -> a
head (SOne a) = a
head (SMany a _ _) = a

tail : NonEmptySortedList a po _ -> SortedList a po
tail (SOne _) = Empty
tail (SMany _ _ xs) = NonEmpty xs

max : {m : a} -> NonEmptySortedList a _ m -> a
max {m} _ = m

newMax : (Ordered a po) => SortedList a po -> a -> a
newMax Empty x = x
newMax (NonEmpty xs) x = either (const x)
                                (const (max xs))
                                (order {to = po} x (max xs))

either' :  {P : Either a b -> Type}
        -> (f : (l : a) -> P (Left l))
        -> (g : (r : b) -> P (Right r))
        -> (e : Either a b) -> P e
either' f g (Left l) = f l
either' f g (Right r) = g r

sinsert :  (Ordered a po)
        => (x : a)
        -> (xs : SortedList a po)
        -> NonEmptySortedList a po (newMax xs x)
sinsert x y with (y)
  | Empty = SOne {po = po} x
  | (NonEmpty xs) = either' { P = NonEmptySortedList a po
                            . either (const x) (const (max xs))
                            }
                            insHead
                            insTail
                            (order {to = po} x (max xs))
  where insHead : po x (max xs) -> NonEmptySortedList a po x
        insHead p = SMany x p xs
        max_lt_newmax : po (max xs) x -> po (max xs) (newMax (tail xs) x)
        max_lt_newmax max_xs_lt_x with (xs)
          | (SOne _) = max_xs_lt_x
          | (SMany _ max_xs_lt_max_xxs xxs)
            = either' { P = po (max xs) . either (const x)
                                                 (const (max xxs))}
                      (const {a = po (max xs) x} max_xs_lt_x)
                      (const {a = po (max xs) (max xxs)} max_xs_lt_max_xxs)
                      (order {to = po} x (max xxs))
        insTail : po (max xs) x -> NonEmptySortedList a po (max xs)
        insTail p = SMany (max xs)
                          (max_lt_newmax p)
                          (sinsert x (assert_smaller y (tail xs)))

insSort :  (Ordered a po) => List a -> SortedList a po
insSort = foldl (\xs, x => NonEmpty (sinsert x xs)) Empty

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM