出于脚本的目的,我想查询agda编译器关于agda源文件中函数的定义。我想问一个问题: X 命名的函数是否依赖于某个洞? (即它是“完整的证据”,还是“正在进行的证明”)。其中 X 是源文件中函数的名称。
例如,请使用以下示例源文件:
open import Relation.Binary.PropositionalEquality
postulate
A : Set
x : A
y : A
z : A
q1 : x ≡ y
q2 : y ≡ z
pf1 : x ≡ z
pf1 = trans q1 q2
pf2 : z ≡ x
pf2 rewrite q1 | q2 = refl
我希望能够(在我的脚本中)确定pf2
是否依赖任何漏洞?在这种情况下,答案是否定的。
或者,假设该文件类似于:
open import Relation.Binary.PropositionalEquality
postulate
A : Set
x : A
y : A
z : A
q1 : x ≡ y
q2 : y ≡ z
pf1 : x ≡ z
pf1 = trans q1 q2
lemma1 : z ≡ y
lemma1 = {!!}
pf2 : z ≡ x
pf2 rewrite q1 = lemma1
现在上面提出的问题的回答是“是”:pf2
是不完整的,因为它依赖于一个洞(间接地,通过引理1)。
我知道我可以找到问题的答案:这个agda源文件中有任何函数是否依赖于漏洞。当我们在源文件上运行agda编译器时,如果存在“未解决的交互元素”,则返回状态将为1,如果一切都已完成,则状态将为0。但是,我想知道源文件中特定函数(按名称)是否具有“未解决的交互元数据”的详细信息。
有没有办法做到这一点?
我查看了agda交互模式的源代码(agda-mode emacs代码使用的接口),但似乎为交互模式定义的大多数命令都依赖于字符范围而不是符号,所以我还没有找到从交互模式获取此信息的方法。
编辑:基于user3237465的评论,我研究了使用反射来解决这个问题。看起来它可以工作,但重写有问题。例如,假设我们在emacs中加载了以下文件:
open import Relation.Binary.PropositionalEquality
open import Agda.Builtin.Reflection
postulate
A : Set
x : A
y : A
z : A
q1 : x ≡ y
q2 : y ≡ z
pf1 : x ≡ z
pf1 = trans q1 q2
lemma1 : z ≡ y
lemma1 = {!!}
pf2 : z ≡ x
pf2 rewrite q1 = lemma1
pf3 : z ≡ x
pf3 = trans lemma1 (sym q1)
-- user3237465 suggested this macro.
-- unfortunately, normalizing `test`
-- using this macro still doesn't show
-- information about the contents of
-- lemma1
macro
actualQuote : Term -> Term -> TC _
actualQuote term hole =
bindTC (normalise term) λ nterm ->
bindTC (quoteTC nterm) (unify hole)
test = actualQuote pf2
test2 = actualQuote pf3
test3 = actualQuote pf1
如果我输入C-c C-n并输入quoteTC pf3
,则会输出quoteTC (trans ?0 (sym q1))
。这就是我想要的,因为它表明证据取决于一个洞。
另一方面,如果我输入C-c C-n并输入quoteTC pf2
,则输出quoteTC (pf2 | x | q1)
。因此,规范化过程似乎无法通过重写。
有没有人知道是否有解决方法?
EDIT2:使用user3237465宏的pf2标准化是:
def (quote .test4.rewrite-20)
(arg (arg-info visible relevant)
(def (quote x) .Agda.Builtin.List.List.[])
.Agda.Builtin.List.List.∷
arg (arg-info visible relevant)
(def (quote q1) .Agda.Builtin.List.List.[])
.Agda.Builtin.List.List.∷ .Agda.Builtin.List.List.[])
答案 0 :(得分:2)
这个答案是关于使用反射来解决问题。
您尝试中缺少的是使用getDefinition
查看已定义的函数。
以下是使用agda-prelude(https://github.com/UlfNorell/agda-prelude)的完整示例,因为我没有时间用标准库(读者练习)来做这件事。
open import Prelude
open import Tactic.Reflection
open import Control.Monad.State
open import Container.Traversable
我们需要跟踪我们已经查看过哪些名称以避免在递归函数上循环,所以让我们使用状态monad。
M = StateT (List Name) TC
runM : {A : Set} → M A → TC A
runM m = fst <$> runStateT m []
isVisited : Name → M Bool
isVisited x = gets (elem x)
setVisited : Name → M ⊤
setVisited x = _ <$ modify (x ∷_)
anyM : {A : Set} → (A → M Bool) → List A → M Bool
anyM p xs = foldr _||_ false <$> traverse p xs
不幸的是,我们无法说服终止检查器只能存在有限数量的已定义函数,所以让我们作弊。如果我们没有深度,那么无作弊选项将设置深度限制并返回true(或不知道)。
{-# TERMINATING #-}
anyMetas : Term → M Bool
checkClause : Clause → M Bool
checkClause (clause ps t) = anyMetas t
checkClause (absurd-clause ps) = return false
checkName : Name → M Bool
checkName f = do
false ← isVisited f
where true → return false
function cs ← lift (getDefinition f)
where _ → return false
anyM checkClause cs
我忍不住对checkName
使用do-notation,因为它使代码变得更好。如果您没有从github构建最新的Agda,可以使用注释代码:
-- caseM isVisited f of λ where
-- true → return false
-- false → setVisited f >>
-- (caseM lift (getDefinition f) of λ where
-- (function cs) → anyM checkClause cs
-- _ → return false)
anyMetaArgs = anyM (anyMetas ∘ unArg)
checkSort : Sort → M Bool
checkSort (set t) = anyMetas t
checkSort (lit n) = return false
checkSort unknown = return false
anyMetas (var x args) = anyMetaArgs args
anyMetas (con c args) = anyMetaArgs args
anyMetas (def f args) = (| checkName f || anyMetaArgs args |)
anyMetas (lam v t) = anyMetas (unAbs t)
anyMetas (pat-lam cs args) = (| anyM checkClause cs || anyMetaArgs args |)
anyMetas (pi a b) = (| anyMetas (unArg a) || anyMetas (unAbs b) |)
anyMetas (agda-sort s) = checkSort s
anyMetas (lit l) = return false
anyMetas (meta x x₁) = return true
anyMetas unknown = return false
使用anyMetas
函数,我们可以定义一个带有名称的宏,并返回一个布尔值,指示名称是否取决于元。
macro
dependsOnMeta? : Name → Term → TC ⊤
dependsOnMeta? x hole = unify hole =<< quoteTC =<< runM (anyMetas (def x []))
您的测试用例现在通过
postulate
A : Set
x : A
y : A
z : A
q1 : x ≡ y
q2 : y ≡ z
pf1 : x ≡ z
pf1 = trans q1 q2
lemma1 : z ≡ y
lemma1 = {!!}
pf2 : z ≡ x
pf2 rewrite q1 = lemma1
pf3 : z ≡ x
pf3 = trans lemma1 (sym q1)
test1 : dependsOnMeta? pf1 ≡ false
test1 = refl
test2 : dependsOnMeta? pf2 ≡ true
test2 = refl
test3 : dependsOnMeta? pf3 ≡ true
test3 = refl