【问题标题】:How do I prove a "seemingly obvious" fact when relevant types are abstracted by a lambda in Idris?当 Idris 中的 lambda 抽象相关类型时,我如何证明“看似显而易见”的事实?
【发布时间】:2025-11-25 00:05:02
【问题描述】:

我正在 Idris 中编写一个基本的单子解析器,以适应 Haskell 的语法和差异。我有基本的工作正常,但我坚持尝试为解析器创建 VerifiedSemigroup 和 VerifiedMonoid 实例。

事不宜迟,下面是解析器类型、Semigroup 和 Monoid 实例,以及 VerifiedSemigroup 实例的开始。

data ParserM a          = Parser (String -> List (a, String))
parse                   : ParserM a -> String -> List (a, String)
parse (Parser p)        = p
instance Semigroup (ParserM a) where
    p <+> q             = Parser (\s => parse p s ++ parse q s)
instance Monoid (ParserM a) where
    neutral             = Parser (const []) 
instance VerifiedSemigroup (ParserM a) where
    semigroupOpIsAssociative (Parser p) (Parser q) (Parser r) = ?whatGoesHere

intros 之后我基本上被卡住了,具有以下证明者状态:

-Parser.whatGoesHere> intros
----------              Other goals:              ----------
{hole3},{hole2},{hole1},{hole0}
----------              Assumptions:              ----------
 a : Type
 p : String -> List (a, String)
 q : String -> List (a, String)
 r : String -> List (a, String)
----------                 Goal:                  ----------
{hole4} : Parser (\s => p s ++ q s ++ r s) =
          Parser (\s => (p s ++ q s) ++ r s)
-Parser.whatGoesHere> 

看起来我应该能够以某种方式将rewriteappendAssociative 一起使用, 但我不知道如何“进入”lambda \s

无论如何,我被困在练习的定理证明部分 - 我似乎找不到太多以 Idris 为中心的定理证明文档。我想也许我需要开始查看 Agda 教程(尽管 Idris 是我确信我想学习的依赖类型语言!)。

【问题讨论】:

  • 要使用 lambda,您需要 函数扩展性 (funext : (f, g : a -&gt; b) -&gt; ((x : a) -&gt; f x = g x) -&gt; f = g)。遗憾的是,Agda 和 Idris(据我所知)都无法证明这个陈述,所以它必须被假定为一个公理。另一种选择是引入您自己的平等概念(例如p = q &lt;=&gt; forall s. parse p s = parse q s),但我认为 Idris 的 VerifiedSemigroup 无法处理自定义平等。
  • 谢谢!这在一定程度上澄清了一些事情。了解术语,function extensionality 引导我对这个想法进行一些更深入的解释。看起来我会在某个地方或其他地方依赖一个公理来让这个经过验证的实例工作——至少现在是这样。所以我不完全有信心如何继续 - funext = believe me 似乎是在作弊 - 再说一次,对于一个玩具问题,我需要一个严格的证据,在我过去尝试使用其他语言时,如果有的话,只有在 cmets 中才有任何形式的证明。
  • 既然还没有答案:你想让我把评论变成实际答案吗?
  • 我还没有时间真正尝试使用您的答案解决问题。我正计划尝试解决这个问题,然后更新我的问题,但工作和夏季学期期末考试来了。如果你有解决方案,我一定很想看看!

标签: agda theorem-proving idris


【解决方案1】:

简单的答案是你不能。在内涵类型理论中,关于函数的推理是相当尴尬的。例如,Martin-Löf 的类型论无法证明:

S x + y = S (x + y)
0   + y = y

x +′ S y = S (x + y)
x +′ 0   = x

_+_ ≡ _+′_  -- ???

(据我所知,这是一个实际的定理,而不仅仅是“缺乏想象力的证明”;但是,我找不到我阅读它的来源)。这也意味着没有更普遍的证据:

ext : ∀ {A : Set} {B : A → Set}
        {f g : (x : A) → B x} →
        (∀ x → f x ≡ g x) → f ≡ g

这称为函数可扩展性:如果你可以证明所有参数的结果相等(即函数在扩展上相等),那么函数也相等。

这将完美解决您遇到的问题:

<+>-assoc : {A : Set} (p q r : ParserM A) →
  (p <+> q) <+> r ≡ p <+> (q <+> r)
<+>-assoc (Parser p) (Parser q) (Parser r) =
  cong Parser (ext λ s → ++-assoc (p s) (q s) (r s))

其中++-assoc_++_ 关联属性的证明。我不确定它在战术中的表现如何,但它会非常相似:为Parser 应用一致性,目标应该是:

(\s => p s ++ q s ++ r s) = (\s => (p s ++ q s) ++ r s)

然后您可以应用扩展性来获得假设 s : String 和目标:

p s ++ q s ++ r s = (p s ++ q s) ++ r s

但是,正如我之前所说,我们没有函数外延性(请注意,这对于一般类型理论来说是不正确的:外延类型理论、同伦类型理论和其他人能够证明这个陈述)。简单的选择是将其假设为公理。与任何其他公理一样,您面临以下风险:

  • 失去一致性(即能够证明错误;虽然我认为函数可扩展性是可以的)

  • 破坏性归约(在给定此公理时,仅针对 refl 进行案例分析的函数会做什么?)

我不确定 Idris 如何处理公理,所以我不会详细说明。请注意,如果您不小心,公理可能会搞砸一些事情。


困难的选择是使用 setoid。 setoid 基本上是一种具有自定义相等性的类型。这个想法是,不是有一个Monoid(或你的情况下的VerifiedSemigroup)适用于内置相等(Idris 中的=,Agda 中的),你有一个特殊的幺半群(或半群) 具有不同的基本相等性。这通常是通过将幺半群(半群)操作与等式和一堆证明打包在一起来完成的,即(在伪代码中):

=   : A → A → Set  -- equality
_*_ : A → A → A    -- associative binary operation
1   : A            -- neutral element

=-refl  : x = x
=-trans : x = y → y = z → x = z
=-sym   : x = y → y = x

*-cong : x = y → u = v → x * u = y * v  -- the operation respects
                                        -- our equality

*-assoc : x * (y * z) = (x * y) * z
1-left  : 1 * x = x
1-right : x * 1 = x

解析器的相等性选择很明确:如果两个解析器的输出对所有可能的输入都一致,则它们是相等的。

-- Parser equality
_≡p_ : {A : Set} (p q : ParserM A) → Set
Parser p ≡p Parser q = ∀ x → p x ≡ q x

这个解决方案有不同的权衡,即新的等式不能完全替代内置的(这往往会在您需要重写某些术语时出现)。但是,如果您只是想证明您的代码做了它应该做的事情(直到一些自定义相等),那就太好了。

【讨论】:

  • 非常感谢您的深入回答!虽然我仍然(显然)需要留出时间在我自己的代码中应用这些想法来真正感受它们,但这个回应给了我一个很好的起点来思考内在类型理论在依赖类型编程中的局限性 -以及如何使用公理或在 setoid 中建立新的平等思想。如果我不是刚开始使用 * 来问这个问题——也就是说,如果我至少有 15 个声望——我也会赞成这个答案。再次感谢!
  • @h.forrest.alexander:别担心。很高兴我能帮上忙!