Zulip Chat Archive
Stream: lean4
Topic: deriving Hashable on recursive inductive
Yuri de Wit (Oct 09 2022 at 19:00):
The builtin deriving handler can deal with this simple recursive inductive:
inductive T
| a
| b (t : T)
deriving Hashable
However, it does not seem to be able to handle the following:
inductive T2
| a
| b (ts : List T2)
deriving Hashable -- ERROR: failed to synthesize instance Hashable (List T2)
Even though there is a Hashable instance for (List α), Lean can't synthesize the instance.
The generated mutual and instance looks good:
mutual
private partial def hashT2✝ (x✝ : @T2) : UInt64✝ :=
match x✝ with
| @T2.a => 0
| @T2.b a✝ => mixHash✝ 1 (hash✝ a✝)
end
instance : Hashable (@T2) := ⟨hashT2✝⟩
But it can't resolve (hash✝ a✝)
for the List argument.
What am I missing here?
Henrik Böving (Oct 09 2022 at 19:05):
the type is not declared as Hashable
during the definition of the function so there is no instance to be found. Instead of recursively calling hash
here it should do something with hashT2 on the list, probably a sort of fold operation.
Yuri de Wit (Oct 09 2022 at 19:13):
I see. I missed the fact that the generated hashT
is calling hashT
directly and not going through typeclass resolution.
Thanks.
Tom (Oct 09 2022 at 23:51):
What option did you specify/what did you write to see that mutual
code? I tried a variety of the pp
flags but can't get the infoview to show it.
Thanks.
Yuri de Wit (Oct 10 2022 at 02:28):
Hi @Tom , I used set_option trace.Elab.Deriving.hashable true
. It will dump the mutual block and the instance.
Yuri de Wit (Oct 10 2022 at 02:50):
Henrik Böving said:
Instead of recursively calling
hash
here it should do something with hashT2 on the list, probably a sort of fold operation.
The fact that the Hashable (List α)
instance is already the needed fold, makes inlining of this fold operation solution unsatisfactory, though. It seems that there needs to be a better solution for these mutual references.
Yuri de Wit (Oct 10 2022 at 13:04):
Yuri de Wit said:
Hi Tom , I used
set_option trace.Elab.Deriving.hashable true
. It will dump the mutual block and the instance.
FYI, here is the deriving handler for Hashable src/Lean/Elab/Deriving/Hashable.lean
(was enlightening to look at):
def mkHashableHandler (declNames : Array Name) : CommandElabM Bool := do
if (← declNames.allM isInductive) && declNames.size > 0 then
let cmds ← liftTermElabM <| mkHashableInstanceCmds declNames
cmds.forM elabCommand
return true
else
return false
Last updated: Dec 20 2023 at 11:08 UTC