由Coq中的推/弹评估器产生的奇怪证明义务

时间:2018-05-13 10:53:26

标签: coq proof dependent-type proof-obligation

我试图在Coq中定义一个简单的基于堆栈的语言。现在,指令集包含push,它会推送nat,而指令pop会弹出一个Prog 2。这个想法是程序是依赖类型的; Require Import Coq.Vectors.VectorDef. Inductive Prog : nat -> Type := | push : forall n : nat, nat -> Prog n -> Prog (S n) | pop : forall n : nat, Prog (S n) -> Prog n. Fixpoint eval (n : nat) (p : Prog n) : t nat n := match p with | push _ n p => cons _ n _ (eval _ p) | pop _ p => match eval _ p with | cons _ _ _ stack => stack end end. 是一个在执行后在堆栈上留下两个元素的程序。

这是通过这个简单的程序实现的:

pop'

我现在想要添加一条指令Inductive Prog : nat -> Type := | push : forall n : nat, nat -> Prog n -> Prog (S n) | pop' : forall n : nat, Prog (S (S n)) -> Prog (S n). ,它弹出一个堆栈元素,但只能在堆栈中至少有两个元素时应用。

Fixpoint

使用与上述相同的pop时(将pop'更改为Program),我收到错误

  

术语"堆栈"有类型" t nat n0"虽然预计会有类型" t nat(S k)"。

所以我认为我可以用Require Import Coq.Program.Tactics Coq.Logic.JMeq. Program Fixpoint eval (n : nat) (p : Prog n) : t nat n := match p with | push _ n p => cons _ n _ (eval _ p) | pop' k p => match eval _ p with | cons _ l _ stack => stack | nil _ => _ end end. 做到这一点。所以我用:

k : nat
p0 : Prog (S k)
p : Prog (S (S k))
Heq_p : JMeq (pop' k p) p0
l, n0 : nat
stack : t nat n0
h : nat
t : t nat n0
Heq_anonymous0 : JMeq (cons nat l n0 stack) (cons nat h n0 t)
______________________________________(1/1)
n0 = S k

然而,出于某种原因,这产生了奇怪的义务,我认为这些义务无法解决。自动尝试后剩下的第一个(两个)义务是:

k

我没有看到链接Progn0的类型参数)和t的方法,Program是矢量类型的类型参数 import UIKit import GoogleMaps import Firebase import FirebaseMessaging import FirebaseInstanceID import UserNotifications extension UIApplication { var statusBarView: UIView? { return value(forKey: "statusBar") as? UIView } } @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? let gcmMessageIDKey = "gcm.message_id" //app ko orientaton lock garna ko lagi var orientationLock = UIInterfaceOrientationMask.all func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return self.orientationLock } func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. //color leteral gives this opetion to choose any color UINavigationBar.appearance().barTintColor = #colorLiteral(red: 0, green: 0.6509803922, blue: 1, alpha: 1) UINavigationBar.appearance().barStyle = .blackOpaque UINavigationBar.appearance().tintColor = .white UINavigationBar.appearance().titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white] UINavigationBar.appearance().isTranslucent = false UIApplication.shared.statusBarView?.backgroundColor = #colorLiteral(red: 0.2470588235, green: 0.5960784314, blue: 1, alpha: 1) GMSServices.provideAPIKey("AIzaSyBIeSGY5VrX20SAoXlstSZD6OBAvrw1dr8") FirebaseApp.configure() // [START set_messaging_delegate] Messaging.messaging().delegate = self // [END set_messaging_delegate] // Register for remote notifications. This shows a permission dialog on first run, to // show the dialog at a more appropriate time move this registration accordingly. // [START register_for_notifications] if #available(iOS 10.0, *) { // For iOS 10 display notification (sent via APNS) UNUserNotificationCenter.current().delegate = self let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] UNUserNotificationCenter.current().requestAuthorization( options: authOptions, completionHandler: {_, _ in }) // [START set_messaging_delegate] Messaging.messaging().delegate = self } else { let settings: UIUserNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound,], categories: nil) application.registerUserNotificationSettings(settings) } application.registerForRemoteNotifications() // [END register_for_notifications] return true } // [START receive_message] func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) { // If you are receiving a notification message while your app is in the background, // this callback will not be fired till the user taps on the notification launching the application. // TODO: Handle data of notifications // With swizzling disabled you must let Messaging know about the message, for Analytics Messaging.messaging().appDidReceiveMessage(userInfo) Messaging.messaging().subscribe(toTopic: "/topics/notification") // Print message ID. if let messageID = userInfo[gcmMessageIDKey] { print("Message ID: \(messageID)") } // Print full message. print(userInfo) } func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { // If you are receiving a notification message while your app is in the background, // this callback will not be fired till the user taps on the notification launching the application. // TODO: Handle data of notification // With swizzling disabled you must let Messaging know about the message, for Analytics // Messaging.messaging().appDidReceiveMessage(userInfo) // Print message ID. if let messageID = userInfo[gcmMessageIDKey] { print("Message ID: \(messageID)") } // Print full message. print(userInfo) completionHandler(UIBackgroundFetchResult.newData) } // [END receive_message] func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { print("Unable to register for remote notifications: \(error.localizedDescription)") } // This function is added here only for debugging purposes, and can be removed if swizzling is enabled. // If swizzling is disabled then this function must be implemented so that the APNs token can be paired to // the FCM registration token. func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { print("APNs token retrieved: \(deviceToken)") Messaging.messaging().apnsToken = deviceToken print("Token is here \(String(describing: Messaging.messaging().fcmToken))") print("Token is here \(String(describing: Messaging.messaging().apnsToken))") if UserDefaults.standard.object(forKey: "FCM_Token") == nil { UserDefaults.standard.set(Messaging.messaging().fcmToken, forKey: "FCM_Token") } else { let fcmSavedToken = UserDefaults.standard.value(forKey: "FCM_Token") as! String if fcmSavedToken == Messaging.messaging().fcmToken { } else { UserDefaults.standard.set(Messaging.messaging().fcmToken, forKey: "FCM_Token") } } // With swizzling disabled you must set the APNs token here. // Messaging.messaging().apnsToken = deviceToken // With swizzling disabled you must set the APNs token here. // Messaging.messaging().apnsToken = deviceToken } func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. Messaging.messaging().shouldEstablishDirectChannel = false } func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. FBHandler() } @objc func refreshToken(notification : NSNotification){ let refreshToken = InstanceID.instanceID().token()! print("*** \(refreshToken) ***") FBHandler() } func FBHandler(){ Messaging.messaging().shouldEstablishDirectChannel = true } } // [START ios_10_message_handling] @available(iOS 10, *) extension AppDelegate : UNUserNotificationCenterDelegate { // Receive displayed notifications for iOS 10 devices. func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { let userInfo = notification.request.content.userInfo // With swizzling disabled you must let Messaging know about the message, for Analytics // Messaging.messaging().appDidReceiveMessage(userInfo) // Print message ID. if let messageID = userInfo[gcmMessageIDKey] { print("Message ID: \(messageID)") } // Print full message. print(userInfo) // Change this to your preferred presentation option completionHandler([.alert, .badge, .sound]) } func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { let userInfo = response.notification.request.content.userInfo // Print message ID. if let messageID = userInfo[gcmMessageIDKey] { print("Message ID: \(messageID)") } // Print full message. print(userInfo) completionHandler([.alert, .badge, .sound]) } } // [END ios_10_message_handling] extension AppDelegate : MessagingDelegate { // [START refresh_token] func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) { print("Firebase registration token: \(fcmToken)") Messaging.messaging().subscribe(toTopic: "/topics/notification") // TODO: If necessary send token to application server. // Note: This callback is fired at each app startup and whenever a new token is generated. } // [END refresh_token] // [START ios_10_data_message] // Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground. // To enable direct data messages, you can set Messaging.messaging().shouldEstablishDirectChannel to true. func messaging(_ messaging: Messaging, didReceive remoteMessage: ) { //Messaging.messaging().shouldEstablishDirectChannel = true print("Received data message: \(remoteMessage.appData)") } }

为什么这个{{1}}会产生这种奇怪的义务,我怎样才能编写绕过这个问题的评估函数呢?

3 个答案:

答案 0 :(得分:2)

在回答您的问题之前,请注意不可能用您的语言编写任何程序! (它对你描述的问题没有任何影响,但无论如何仍然值得指出......)

From Coq Require Import Vectors.Vector.

Set Implicit Arguments.

Inductive Prog : nat -> Type :=
  | push : forall n : nat, nat -> Prog n -> Prog (S n)
  | pop' : forall n : nat, Prog (S (S n)) -> Prog (S n).

Fixpoint not_Prog n (p : Prog n) : False :=
  match p with
  | push _ p' => not_Prog p'
  | pop'   p' => not_Prog p'
  end.

现在,问你的问题。正是由于这个和相关的问题,许多人更喜欢在Coq中避免这种编程风格。在这种情况下,我发现使用tl编写函数更容易,它会提取向量的尾部。

From Coq Require Import Vectors.Vector.

Set Implicit Arguments.

Inductive Prog : nat -> Type :=
  | empty : Prog 0
  | push : forall n : nat, nat -> Prog n -> Prog (S n)
  | pop' : forall n : nat, Prog (S (S n)) -> Prog (S n).

Fixpoint eval (n : nat) (p : Prog n) : t nat n :=
  match p with
  | empty    => nil _
  | push n p => cons _ n _ (eval p)
  | pop'   p => tl (eval p)
  end.

如果您仍然有兴趣在Coq中使用这种数据类型,您可能需要查看Equations插件,它为依赖模式匹配提供了更好的支持。

答案 1 :(得分:1)

我无法让Program Fixpoint记住适当的平等,但这是一个使用战术的定义,我们可以使用remember围绕等式证明创建一个护航模式。证明术语中的两个子证据由abstract生成;它们都是关于构造函数的非常简单的证明。

Fixpoint eval (n : nat) (p : Prog n) : t nat n.
  refine (match p with
          | push n' v p' => cons _ v _ (eval _ p')
          | pop' n' p' => _
          end).
  set (x := eval _ p').
  remember (S (S n')).
  destruct x.
  abstract congruence. (* nil case *)
  assert (n0 = S n') by (abstract congruence).
  rewrite H in x.
  exact x.
Defined.

Print eval.
(*
eval =
fix eval (n : nat) (p : Prog n) {struct p} :
t nat n :=
  match p in (Prog n0) return (t nat n0) with
  | push n' v p' => cons nat v n' (eval n' p')
  | pop' n' p' =>
      let x := eval (S (S n')) p' in
      let n0 := S (S n') in
      let Heqn0 : n0 = S (S n') := eq_refl in
      match
        x in (t _ n1)
        return (n1 = S (S n') -> Prog n1 -> t nat (S n'))
      with
      | nil _ =>
          fun (Heqn1 : 0 = S (S n')) (_ : Prog 0) =>
          eval_subproof n' Heqn1
      | cons _ _ n1 x0 =>
          fun (Heqn1 : S n1 = S (S n')) (_ : Prog (S n1)) =>
          let H : n1 = S n' := eval_subproof0 n' n1 Heqn1 in
          let x1 :=
            eq_rec n1 (fun n2 : nat => t nat n2) x0 (S n') H in
          x1
      end Heqn0 p'
  end
     : forall n : nat, Prog n -> t nat n
*)

答案 2 :(得分:1)

这是尝试使用方程式。

From Coq Require Import Vector.
From Equations Require Import Equations.

Equations eval (n : nat) (p : Prog n) : t nat n :=
  eval _ (push _ n p) := cons n (eval _ p);
  eval _ (pop' _ p) <= eval _ p => {
    eval _ (pop' _ p) (cons _ stack) := stack }.

但请注意,我并不完全确定我在做什么。