在Coq中计算列表中不同元素的数量

  • 本文关键字:元素 Coq 计算 列表 coq
  • 更新时间 :
  • 英文 :


我正在尝试编写一个函数,该函数接受自然数列表并返回其中不同元素的数量作为输出。例如,如果我有列表 [1,2,2,4,1],我的函数 DifElem 应该输出"3"。我尝试了很多东西,我得到的最接近的是:

Fixpoint DifElem (l : list nat) : nat :=
   match l with
   | [] => 0
   | m::tm => 
   let n := listWidth tm in
   if (~ In m tm) then S n else n
end.

我的逻辑是这样的:如果 m 不在列表的尾部,则在计数器中添加一个。如果是,请不要添加到计数器中,所以我只会数一次:当它是最后一次出现时。我收到错误:

Error: The term "~ In m tm" has type "Prop"
which is not a (co-)inductive type.

In 是 Coq 列表标准库的一部分 Coq.Lists.List. 它在那里被定义为:

Fixpoint In (a:A) (l:list A) : Prop :=
   match l with
   | [] => False
   | b :: m => b = a / In a m
end.

我想我不太了解如何在定义中使用 If then 语句,Coq 的文档不够有用。

我还用来自同一库中的nodup尝试了这个定义:

Definition Width (A : list nat ) := length (nodup ( A ) ).

在这种情况下,我得到的错误是:

The term "A" has type "list nat" while it is expected to have
type "forall x y : ?A0, {x = y} + {x <> y}".

我对这里发生的事情感到困惑。感谢您帮助您解决此问题。

你似乎混淆了命题(Prop)和布尔值(bool)。我将尝试用简单的术语来解释:命题是你证明的东西(根据Martin-Lof的解释,它是一组证明),布尔值是一个只能保存2个值(true/false)的数据类型。布尔值在计算中很有用,当只有两种可能的结果并且不需要附加信息时。您可以在本回答中找到有关此主题的更多信息 @Ptival 或在 B.C. Pierce 等人的《软件基础》一书中找到有关此主题的完整部分(请参阅命题和布尔值部分)。

实际上,nodup是这里要走的路,但 Coq 希望您提供一种决定输入列表元素相等的方法。如果你看一下nodup的定义:

Hypothesis decA: forall x y : A, {x = y} + {x <> y}.
Fixpoint nodup (l : list A) : list A :=
  match l with
    | [] => []
    | x::xs => if in_dec decA x xs then nodup xs else x::(nodup xs)
  end.  

您会注意到一个假设decA,它成为nodup函数的附加参数,因此您需要传递eq_nat_dec(可判定相等式nats),例如:nodup eq_nat_dec l

因此,这是一个可能的解决方案:

Require Import Coq.Arith.Arith.
Require Import Coq.Lists.List.
Import ListNotations.
Definition count_uniques (l : list nat) : nat :=
  length (nodup eq_nat_dec l).
Eval compute in count_uniques [1; 2; 2; 4; 1].
(* = 3 : nat *)

注意nodup函数从Coq v8.5开始工作。

除了使用标准库的 Anton 解决方案之外,我还想指出,mathcomp 为这个用例提供了特别好的支持,以及关于countuniq的相当完整的理论。您的函数变为:

From mathcomp Require Import ssreflect ssrfun ssrbool eqtype ssrnat seq.
Definition count_uniques (T : eqType) (s : seq T) := size (undup s).

事实上,我认为count_uniques名称是多余的,我更喜欢在需要时直接使用size (undup s)

使用集合:

Require Import MSets.
Require List. Import ListNotations.
Module NatSet := Make Nat_as_OT.
Definition no_dup l := List.fold_left (fun s x => NatSet.add x s) l NatSet.empty.
Definition count_uniques l := NatSet.cardinal (no_dup l).
Eval compute in count_uniques [1; 2; 2; 4; 1].

最新更新