Zulip Chat Archive

Stream: lean4

Topic: Failed to synthesize instance ToString Term


Yuri de Wit (Feb 18 2022 at 21:00):

I am getting an error trying to define the ToString instance of my Term here: Failed to synthesize instance ToString Term.

Does this just mean I can't define the ToString instance and used it at the same time and that I need to extract the toString logic as a separate definition?

inductive Term where
  | Var (name : String)
  | Dup (nam0 : String) (name1 : String) (expr : Term) (body : Term)
  | Let (name : String) (expr : Term) (body : Term)
  | Lam (name : String) (body : Term)
  | App (func : Term) (argm : Term)
  | Ctr (name : String) (args: Array Term)
  | U32 (numb : UInt64)
  | Op2 (oper : Operation) (val0 : Term) (val1 : Term)

instance : ToString Term where
  toString
  | Term.Var n => s!"{n}"
  | Term.Dup n0 n1 e b => s!"dup {n0} {n1} = {e} {b}"
  | Term.Let n e b => s!"let {n} = {e}; {b}"
  | Term.Lam n b => s!"λ{n} {b}"
  | Term.App f a => s!"({f} {a})"
  | Term.Ctr n a => s!"{n}"
  | Term.U32 n => s!"{n}"
  | Term.Op2 op v0 v1 => s!"({op} {v0} {v1})"

instance : ToString Term where
  toString
  | Term.Var n => s!"{n}"
  | Term.Dup n0 n1 e b => s!"dup {n0} {n1} = {e} {b}"
  | Term.Let n e b => s!"let {n} = {e}; {b}"
  | Term.Lam n b => s!"λ{n} {b}"
  | Term.App f a => s!"({f} {a})"
  | Term.Ctr n a => s!"{n}"
  | Term.U32 n => s!"{n}"
  | Term.Op2 op v0 v1 => s!"({op} {v0} {v1})"

Alexander Bentkamp (Feb 18 2022 at 21:50):

I seems that you can't. Here's a hack that allows you to use the s! notation recursively:

partial instance : ToString Term where
  toString :=
    let rec toStr x :=
      have : ToString Term := toStr
      match x with
      | Term.Var n => s!"{n}"
      | Term.Dup n0 n1 e b => s!"dup {n0} {n1} = {e} {b}"
      | Term.Let n e b => s!"let {n} = {e}; {b}"
      | Term.Lam n b => s!"λ{n} {b}"
      | Term.App f a => s!"({f} {a})"
      | Term.Ctr n a => s!"{n}"
      | Term.U32 n => s!"{n}"
      | Term.Op2 op v0 v1 => s!"({op} {v0} {v1})"
    toStr

But it only gives you a partial instance. Maybe you can prove it terminating somehow, but I don't know how.

Yuri de Wit (Feb 18 2022 at 22:04):

Thank you!

So, even though there are a few cases that are not recursive, the inductive type can always be infinite. It seems that unless I can add some sort of tree height check or something like that I would never be able to prove termination (assuming I understand your point correctly)

In this case, shouldn't partial be enough to define my instance without the alternative you provided?

Alexander Bentkamp (Feb 19 2022 at 08:44):

Since the recursive calls occur only on smaller terms, it should be possible to somehow prove termination, I just don't know how.

Alexander Bentkamp (Feb 19 2022 at 08:45):

Should partial be enough to do the job? I don't know. Currently, the new instance gets registered only when the command is completed. Maybe the instance command could be extended to allow this recursive behavior.


Last updated: Dec 20 2023 at 11:08 UTC