我怎样才能让 Coq 相信我的函数实际上是递归的?

How can I convince Coq that my function is in fact recursive?

我正在尝试用 Coq 编写一个程序来解析相对简单的上下文无关语法(一种括号),我的通用算法是让解析器潜在地 return 字符串的其余部分.例如,解析 "++]>><<" 应该 return CBTerminated [Incr Incr] ">><<" 然后,假设正在解析“[++]>><<”的解析器将能够获取“>>” <" 并继续。

很明显,字符串变小了,但让 Coq 相信这是另一回事。它给我错误

Recursive definition of parseHelper is ill-formed. [...] Recursive call to parseHelper has principal argument equal to "rest'" instead of "rest".

我认为这意味着它不相信 rest' < input 就像它相信 rest < input 一样。 (其中 < 表示 "is smaller than")。

我曾想过 return计算要跳过的字符数,但这似乎相当不雅且不必要。

Require Import Coq.Strings.String.
Require Import Coq.Strings.Ascii.
Require Import Coq.Lists.List.
Require Import ZArith.

Open Scope char_scope.
Open Scope list_scope.

Notation " [ ] " := nil (format "[ ]") : list_scope.
Notation " [ x ] " := (cons x nil) : list_scope.
Notation " [ x ; y ; .. ; z ] " := (cons x (cons y .. (cons z nil) ..)) : list_scope.

Inductive BF :=
    | Incr : BF
    | Decr : BF
    | Left : BF
    | Right : BF
    | In : BF
    | Out : BF
    | Sequence : list BF -> BF
    | While : BF -> BF.

Inductive BF_Parse_Result :=
    | UnmatchedOpen
    | EOFTerminated (u : list BF)
    | CBTerminated (u : list BF) (rest : string).

Definition bind (val : BF) (onto : BF_Parse_Result) :=
    match onto with
        | UnmatchedOpen => UnmatchedOpen
        | EOFTerminated values => EOFTerminated (cons val values)
        | CBTerminated values rest => CBTerminated (cons val values) rest
    end.

Fixpoint parseHelper (input : string) : BF_Parse_Result :=
    match input with
        | EmptyString => EOFTerminated nil
        | String first rest =>
             match first with
                 | "+" => bind Incr (parseHelper rest)
                 | "-" => bind Decr (parseHelper rest)
                 | "<" => bind Left (parseHelper rest)
                 | ">" => bind Right (parseHelper rest)
                 | "," => bind In (parseHelper rest)
                 | "." => bind Out (parseHelper rest)
                 | "]" => CBTerminated nil rest
                 | "[" =>
                     match parseHelper rest with
                         | UnmatchedOpen => UnmatchedOpen
                         | EOFTerminated _ => UnmatchedOpen
                         | CBTerminated vals rest' =>
                             bind (While (Sequence vals)) (parseHelper rest')
                     end
                 | _ => parseHelper rest
             end
    end.

您是否考虑过使用 well-founded recursion? Coq's standard library has a series of useful combinators for defining functions over well-founded relations. Reference 1 展示了两种用于一般递归的技术(有根据的递归和 monad)。

其他在 Agda 上下文中也非常有用的技术,就是所谓的 Bove-Capretta method,它定义了一个模仿已定义函数调用图的归纳谓词。

Coq 还有 Function 命令可以用来定义更通用的递归函数。每当我需要定义非结构递归函数时,我都会使用有根据的递归。

希望对您有所帮助。