Zulip Chat Archive

Stream: general

Topic: reduce v eval


Kevin Buzzard (Feb 18 2025 at 12:51):

I never use #reduce or #eval but I'm about to do a demo in front of a bunch of computer scientists and I noticed this:

namespace KCL -- so as not to clash with `List` in root namespace

inductive List (α : Type)
| nil : List α
| cons (a : α) (L : List α) : List α

namespace List

def L : List Nat := cons 2 (cons 37 nil)

#reduce L -- cons 2 (cons 37 nil)
#eval L -- KCL.List.cons 2 (KCL.List.cons 37 (KCL.List.nil))

I was surprised the results were different (and this is somehow confusing). Does #eval not care about namespaces but #reduce does for some reason?

Eric Wieser (Feb 18 2025 at 12:55):

The main difference here is that #reduce is printing an interactive expression, but #eval is printing a string

Kyle Miller (Feb 18 2025 at 17:26):

Add a deriving Lean.ToExpr, and they have the same output:

import Lean

namespace KCL -- so as not to clash with `List` in root namespace

inductive List (α : Type)
| nil : List α
| cons (a : α) (L : List α) : List α
deriving Lean.ToExpr

namespace List

def L : List Nat := cons 2 (cons 37 nil)

#reduce L -- cons 2 (cons 37 nil)
#eval L -- cons 2 (cons 37 nil)

Arthur Paulino (Feb 18 2025 at 21:28):

Oh wow, I didn't know Lean.ToExpr was a deriving handle. This is amazingly useful!
cc @John Burnham

Kyle Miller (Feb 19 2025 at 19:18):

(Thanks to @Alex Keizer for his work to get this into Lean core!)

Kyle Miller (Feb 19 2025 at 19:23):

Currently, the reason #eval L worked is that #eval can auto-derive a Repr instance. That frees you from needing to add deriving Repr for a one-off #eval.

I was thinking of having #eval be able to auto-derive a ToExpr instances as well. I haven't been completely sure whether it would be surprising to use an auto-derived ToExpr instance over a user-defined Repr instance. (I'm sure that there will be a question down the line of "why isn't my Repr instance being used here?")

Mario Carneiro (Feb 20 2025 at 09:40):

isn't a possible solution to that to prefer to use a Repr instance if one can be found, and only then try auto-deriving ToExpr and Repr?

Kyle Miller (Feb 20 2025 at 18:10):

Yeah, that's a possible solution and is under consideration too. That also has the issue where people ask "why isn't this #eval output hoverable?" or "why does this #eval give different-looking output from #reduce" (I'm less inclined to worry about this last question because of how different the evaluation models are)

Another thing to throw in is that it would be nice if #eval would add in instances for types that have no representation, with a hover explaining why not (maybe it's a function type) or what instances are missing. There's also the possibility of having recursive derivation too.

Mario Carneiro (Feb 20 2025 at 21:45):

ideally hoverable #eval output should be addressed by having an even more rich text format class being preferred if available, I guess ToMessageData is the relevant one in this case

Mario Carneiro (Feb 20 2025 at 21:51):

maybe it should even be possible to evaluate to a widget, so we can be like mathematica
image.png

Kevin Buzzard (Feb 20 2025 at 22:00):

I daren't ask what kind of graph product sends two graphs with three vertices to a graph with six vertices...

Kyle Miller (Feb 20 2025 at 22:03):

I think there's a planar immersion failure here...

Kyle Miller (Feb 20 2025 at 22:07):

To get something mathematica-like, one approach could be to have a separate Syntax formatting path that outputs something richer. Syntax is basically what Mathematica operates on anyway, so it has to be possible to make a "StandardForm" formatter that outputs widgets, maybe in conjunction with some delaborator configuration option to make sure the output Syntax is formattable. (I know this is sort of hacky, but this would let us take advantage of the pre-existing core delaborators.)


Last updated: May 02 2025 at 03:31 UTC