`--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
, wheree0
ande1
are bound variables, wheref
pattern matches on its parameter. - Substitute
literals intoexpressions intoe0
ande1
e0
ande1
, 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.