agda / agda

Agda is a dependently typed programming language / interactive theorem prover.

Home Page:https://wiki.portal.chalmers.se/agda/pmwiki.php

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`--lossy-unification` doesn't fall back to regular unification when instances are used

Thrithralas opened this issue · comments

Lossy unification seemingly does not fall back to regular unification if literals are an instance parameter is part of the unification problem.

Steps to Reproduce:

  • Define a Number, IsString etc. instance for an arbitrary type.
  • Create a unification problem of the form f e0 = f e1, where e0 and e1 are bound variables, where f pattern matches on its parameter.
  • Substitute literals into e0 and e1 expressions into e0 and e1, where both sides have an instance parameter, see below
  • Upon reloading the file, Agda raises a type error of the form e0 != e1.

Minimal reproducible example:

Here I choose Bool as the arbitrary type and implemented a simple Number instance for it:

{-# OPTIONS --lossy-unification #-}

open import Agda.Builtin.Nat
open import Agda.Builtin.Bool
open import Agda.Builtin.Equality

record  : Set where
  instance constructor tt

open import Agda.Builtin.FromNat
open import Agda.Builtin.Sigma

instance
  NumBool : Number Bool
  Number.Constraint NumBool _ = ⊤
  Number.fromNat NumBool zero = true
  Number.fromNat NumBool (suc n) = false -- not sure if pattern matching is relevant here


g : Bool  ⊤
g false = tt
g true = tt

f : Σ Bool (λ b  Σ Bool λ b'  g b ≡ g b')
f = 0 , (1 , {!!})

h : ((a b : Bool)  g a ≡ g b  ⊤)  ⊤
h x = x 0 1 {!!}

The greater issue here is that Agda shows that the type of both holes is tt = tt and when refining or using auto, it accepts refl, but upon reloading the file, it fails with a type error of false != true. Removing --lossy-unification or using concrete values instead of literals no longer raises a type error.

The expected behaviour would be for Agda to fall back on regular unification and solve it that way as the documentation states, but for some reason it doesn't.

Can confirm this is an issue starting from 2.6.4.1 and is still an issue on the master branch.

I'll try to verify later whether the instance needs to pattern match on its input parameter later.

Can confirm this is an issue starting from 2.6.4.1 and is still an issue on the master branch.

It seems that is already the behaviour in 2.6.2 when lossy unification is added. So, it never worked, according to my experiments.

This bug can occur with any type class instance, not just overloaded literals.

{-# OPTIONS --lossy-unification #-}

open import Agda.Builtin.Bool
open import Agda.Builtin.Equality
open import Agda.Builtin.Unit
open import Agda.Builtin.Sigma

record C : Set where
  field m : Bool  Bool
open C {{...}}

instance
  i : C
  m {{i}} b = b

g : Bool  ⊤
g false = tt
g true = tt

f : Σ Bool (λ b  Σ Bool λ b'  g b ≡ g b')
f = m false , (m true , {!!})
-- f = m {{i}} false , (m {{i}} true , refl) -- works

I see that the documentation claims that lossy unification always falls back to regular unification, but in practice I don't see how that can ever be true. It seems like this is just an unavoidable consequence of --lossy-unification, and any attempt to fix it would negate the performance benefits that you'd want from the option. But perhaps someone else who has a better idea of how --lossy-unification is supposed to work has a better idea.