从GADT中检索约束,以确保用尽Coq中的模式匹配

时间:2019-06-10 10:59:05

标签: coq dependent-type gadt

让我们定义两种助手类型:

lab_tickets_df.drop(columns = ["0"])

然后还有两个依赖于Inductive AB : Set := A | B. Inductive XY : Set := X | Y. XY的类型

AB

请注意Inductive Wrapped : AB -> XY -> Set := | W : forall (ab : AB) (xy : XY), Wrapped ab xy | WW : forall (ab : AB), Wrapped ab (match ab with A => X | B => Y end) . Inductive Wrapper : XY -> Set := WrapW : forall (xy : XY), Wrapped A xy -> Wrapper xy. 构造函数–它只能是类型WWWrapped A X的值。

现在我想在Wrapped B Y上进行图案匹配:

Wrapper Y

但出现错误

Definition test (wr : Wrapper Y): nat :=
  match wr with
  | WrapW Y w =>
    match w with
    | W A Y => 27
    end
  end.

为什么会发生? Error: Non exhaustive pattern-matching: no clause found for pattern WW _ 强制包含Wrapper的版本为Wrapped,类型签名强制AY的构造函数禁止为WWA同时。我不明白为什么还要考虑这种情况,但我不得不检查这似乎是不可能的。

如何解决这种情况?

2 个答案:

答案 0 :(得分:3)

让我们简化一下:

Inductive MyTy : Set -> Type :=
  MkMyTy : forall (A : Set), A -> MyTy A.

Definition extract (m : MyTy nat) : nat :=
  match m with MkMyTy _ x => S x end.

此操作失败:

The term "x" has type "S" while it is expected to have type "nat".

浪费。

这是因为我说

Inductive MyTy : Set -> Type

与参数相反,这使MyTy的第一个参数的索引为MyTy。带有参数的归纳类型可能看起来像这样:

Inductive list (A : Type) : Type :=
  | nil : list A
  | cons : A -> list A -> list A.

参数在:的左侧命名,而不是每个构造函数的定义中的forall-d。 (它们仍然存在于定义之外的构造函数类型中:cons : forall (A : Type), A -> list A -> list A。)如果我将Set设为MyTy的参数,则可以定义extract

Inductive MyTy (A : Set) : Type :=
  MkMyTy : A -> MyTy A.

Definition extract (m : MyTy nat) : nat :=
  match m with MkMyTy _ x => S x end.

这样做的原因是,在内部,match 忽略您从外部就知道的有关scrutinee索引的任何信息。 (或者,相反,Gallina中的基础match表达式会忽略索引。当您在源代码中编写match时,Coq会尝试将其转换为原始形式,同时并入来自索引的信息,但是它通常会失败。)m : MyTy nat的第一个版本中的extract根本无关紧要。相反,根据构造函数S : Set,匹配项给了我x : S(名称由Coq自动选择)和MkMyTy,而没有提到nat。同时,因为MyTy在第二个版本中有一个参数,所以我实际上得到了x : nat_这次确实是一个占位符;强制将其写为_,因为没有匹配项,您可以Set Asymmetric Patterns使其消失。

我们区分参数和索引的原因是因为参数有很多限制-最值得注意的是,如果I是带有参数的归纳类型,则参数必须在每个构造函数的返回类型中作为变量出现:

Inductive F (A : Set) : Set := MkF : list A -> F (list A).
                                            (* ^--------^ BAD: must appear as F A *)

在您遇到的问题中,我们应该尽可能地设置参数。例如。 match wr with Wrap Y w => _ end位是错误的,因为XY的{​​{1}}参数是一个索引,因此Wrapper的事实将被忽略;您也需要处理wr : Wrapper Y情况。 Coq并没有告诉你。

Wrap X w

现在您的Inductive Wrapped (ab : AB) : XY -> Set := | W : forall (xy : XY), Wrapped ab xy | WW : Wrapped ab (match ab with A => X | B => Y end). Inductive Wrapper (xy : XY) : Set := WrapW : Wrapped A xy -> Wrapper xy. 会(几乎)进行编译:

test

因为具有参数可以为Coq提供Definition test (wr : Wrapper Y): nat := match wr with | WrapW _ w => (* mandatory _ *) match w with | W _ Y => 27 (* mandatory _ *) end end. 详尽的信息,以便使用match索引中的信息。如果您发出Wrapped,您会发现有一些跳跃会通过原始Print test.传递有关索引Y的信息,否则它们将被忽略。 See the reference manual for more information.

答案 1 :(得分:2)

该解决方案虽然简单却棘手:

import java.sql.Timestamp

import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.sql.SparkSession
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.kafka010.ConsumerStrategies.Subscribe
import org.apache.spark.streaming.kafka010.KafkaUtils
import org.apache.spark.streaming.kafka010.LocationStrategies.PreferConsistent
import java.time.{LocalDate, LocalDateTime}
import java.util.Calendar



object SparkKafka {
  def main(args: Array[String]): Unit = {

    val spark = SparkSession
      .builder()
      .appName("test_app")
      .getOrCreate()
    val sparkContext = spark.sparkContext


    val ssc = new StreamingContext(sparkContext, Seconds(1)) // the polling frequency is 2 seconds, can be modified based on the BM requirements.
///val currentHour = now.get(Calendar.HOUR_OF_DAY)

    log.info("Before starting the Stream -->>")
    val stream = KafkaUtils.createDirectStream[String, String](ssc, PreferConsistent, Subscribe[String, String]
      (Array.apply("Kafka_topic_name"), getKafkaParams()))

      .map(record => record.value)

    stream.foreachRDD { rdd =>

      try {
        if (!rdd.isEmpty()) {
          log.info("rdd is not empty and saving to -->>"+LocalDate.now.getYear+"/"+LocalDate.now.getMonth+"/"+LocalDate.now.getDayOfMonth+"/"+LocalDateTime.now().getHour)
          rdd.saveAsTextFile("hdfs:///<folder to save>") //TODO::: Externalize the HDFS location to Props




          LocalDate.now.getMonth


         if (null != args && null != args {
            0
          } && args {
            0
          }.equals("log")) {
            rdd.foreach(x => print("Message read and saved TO S3 bucket----*****--->>" + x))
          }
        }
      } catch {

        case t: Throwable =>
          t.printStackTrace() // TODO: handle error)
          log.error("Exception occured while processing the data exception is {}", t.getCause)
      }
    }

    ssc.start()
    log.info("started now-->> " + compat.Platform.currentTime)
    ssc.awaitTermination()

  }

  def getKafkaParams(): Map[String, Object] = {
    Map[String, Object]("bootstrap.servers" -> "host:port
      "key.deserializer" -> classOf[StringDeserializer],
      "value.deserializer" -> classOf[StringDeserializer],
      "group.id" -> "Group_Name",
      //      "sasl.kerberos.service.name" -> "kafka",
      "auto.offset.reset" -> "latest",
      "enable.auto.commit" -> (true: java.lang.Boolean))
  }

}

问题在于,Coq并未推断出某些必要的不变式以意识到Definition test (wr : Wrapper Y): nat. refine (match wr with | WrapW Y w => match w in Wrapped ab xy return ab = A -> xy = Y -> nat with | W A Y => fun _ _ => 27 | _ => fun _ _ => _ end eq_refl eq_refl end); [ | |destruct a]; congruence. Defined. 情况是荒谬的。我必须明确为其提供证明。

在此解决方案中,我更改了WW以返回一个函数,该函数需要两个证明并将其带到我们实际结果的上下文中:

  • match显然是ab
  • A显然是xy

我已经涵盖了忽略这些假设的真实案例,并且我推迟了“坏”案例,这些案例后来被证明是错误的,后来变得微不足道。我被迫手动通过了Y,但它确实有效,而且看起来还不错。