[Agda] Computation and patterns in called functions

Francesco Mazzoli f at mazzo.li
Mon Jan 28 16:40:34 CET 2013


Hi Nils,

Thanks for the answer.

At Mon, 28 Jan 2013 16:24:16 +0100,
Nils Anders Danielsson wrote:
> There are several solutions:
> 
> * One could perhaps change Agda so that overlapping patterns are
>    replaced with non-overlapping ones before the right-hand sides are
>    type-checked. (I believe that Coq does this.) For instance,
> 
>      _≟_ : (x y : Bool) → Dec (x ≡ y)
>      true  ≟ true  = yes refl
>      false ≟ false = yes refl
>      _     ≟ _     = no (λ ())
> 
>    could be expanded into the following, type-correct code:
> 
>      _≟_ : (x y : Bool) → Dec (x ≡ y)
>      true  ≟ true  = yes refl
>      false ≟ false = yes refl
>      true  ≟ false = no (λ ())
>      false ≟ true  = no (λ ())

That would be great and would also solve the problem that you have to explicitly
pattern match to use absurd patterns.  See
<https://personal.cis.strath.ac.uk/conor.mcbride/pub/Hmm/Hier.agda> for an
extreme instance of this problem.

>    However, it's not quite clear to me what would happen if a duplicated
>    right-hand side contained a goal.

I don’t get what you mean here.  In my case the short version of optExp-correct:

    optExp-correct : ∀ {vs} e → evalExp vs e ≡ evalExp vs (optExp e)
    optExp-correct (plus (const 0) e) = optExp-correct e
    optExp-correct {vs} (plus e₁ e₂) =
      cong₂ _+_ (optExp-correct {vs} e₁) (optExp-correct e₂)
    optExp-correct e = refl

Would get expanded to

    optExp-correct : ∀ {vs} e → evalExp vs e ≡ evalExp vs (optExp e)
    optExp-correct (plus (const 0) e) = optExp-correct e
    optExp-correct {vs} (plus e₁@(const (suc _)) e₂) =
      cong₂ _+_ (optExp-correct {vs} e₁) (optExp-correct e₂)
    optExp-correct {vs} (plus e₁@(var _) e₂) =
      cong₂ _+_ (optExp-correct {vs} e₁) (optExp-correct e₂)
    optExp-correct {vs} (plus e₁@(plus _ _) e₂) =
      cong₂ _+_ (optExp-correct {vs} e₁) (optExp-correct e₂)
    optExp-correct (var _) = refl
    optExp-correct (const _) = refl

Where I’m using haskell-style @, but in Agda you could simply desugar those to
‘let’s.  Maybe I’m missing something...

> * One can use custom eliminators or views. Example (based on your code):
> 
>      data OptExpP : Exp → Set where
>        plus-const-0  : ∀ e → OptExpP (plus (const 0) e)
>        plus          : ∀ e₁ e₂ → e₁ ≢ const 0 → OptExpP (plus e₁ e₂)
>        anything-else : ∀ e → ¬ (∃₂ λ e₁ e₂ → e ≡ plus e₁ e₂) → OptExpP e
> 
>      optExpP : ∀ e → OptExpP e
>      optExpP (const n)                = anything-else (const n) (λ { (_ , _ , ()) })
>      optExpP (var x)                  = anything-else (var x)   (λ { (_ , _ , ()) })
>      optExpP (plus (const zero) e)    = plus-const-0 e
>      optExpP (plus (const (suc n)) e) = plus (const (suc n)) e  (λ ())
>      optExpP (plus (var x) e)         = plus (var x)         e  (λ ())
>      optExpP (plus (plus e₁ e₂) e₃)   = plus (plus e₁ e₂)    e₃ (λ ())
> 
>      optExp : Exp → Exp
>      optExp e with optExpP e
>      optExp .(plus (const 0) e) | plus-const-0 e    = optExp e
>      optExp .(plus e₁ e₂)       | plus e₁ e₂ _      = plus (optExp e₁) (optExp e₂)
>      optExp .e                  | anything-else e _ = e
> 
>      optExp-correct : ∀ {vs} e → evalExp vs e ≡ evalExp vs (optExp e)
>      optExp-correct e with optExpP e
>      optExp-correct .(plus (const 0) e) | plus-const-0 e               = optExp-correct e
>      optExp-correct .(plus e₁ e₂)       | plus e₁ e₂ _                 = cong₂ _+_ (optExp-correct e₁) (optExp-correct e₂)
>      optExp-correct .(const x)          | anything-else (const x)    _ = refl
>      optExp-correct .(var x)            | anything-else (var x)      _ = refl
>      optExp-correct .(plus e₁ e₂)       | anything-else (plus e₁ e₂) p = ⊥-elim (p (e₁ , e₂ , refl))

Yes that works but feels overkill, especially if it’s a one-off proof - which is
often the case.

Francesco


More information about the Agda mailing list