Zulip Chat Archive
Stream: lean4
Topic: evaluate generic term to literal safely?
Thomas Murrills (Feb 11 2023 at 07:44):
Let's say I have some syntax $a:term
that I'm using in a tactic elaboration. I'd like it to be a string literal before I use it, but I'd like it to be able to be specified some other way, e.g. by a prior declaration let myStr := "foo"
or by a computation (so I really do want a term
, or at least want something broader than a str
). How can I unfold all definitions in the course of elaborating the syntax so that I can try to get a string literal?
I've tried using withTransparency .all
before elaborating, using evalTerm
(but it complains that this is unsafe), and a couple other things. (I would have liked to try something like isDefEq (.lit m) aExpr
with m
a metavariable under the appropriate transparency, but then I'd need some hypothetical mkFreshLiteralMVar
instead of mkFreshExprMVar
to make the types work.)
Is there a simple solution I'm missing?
Mario Carneiro (Feb 11 2023 at 07:48):
evalConstCheck
or evalTerm
Mario Carneiro (Feb 11 2023 at 07:52):
import Lean.Elab.Eval
import Std.Util.TermUnsafe
open Lean Meta Elab Command
elab "eval_my_string" s:term : command => do
let s ← liftTermElabM <|
unsafe Term.evalTerm String (.const ``String []) s
logInfo m!"got: {s}"
def head : String := "hello"
eval_my_string head ++ " world"
Mario Carneiro (Feb 11 2023 at 07:53):
and yes, this is unsafe
Thomas Murrills (Feb 11 2023 at 07:59):
Works like a charm! Thanks for pointing me to that Std
file, I probably wouldn't have found that. :)
Thomas Murrills (Feb 11 2023 at 08:00):
As for safety I guess I can just live on the edge? Hopefully any breakages are caught by a standard try
/catch
?
Mario Carneiro (Feb 11 2023 at 08:02):
heh, no unsafe
issues aren't caught by try
/catch
they are likely to crash lean at best
Thomas Murrills (Feb 11 2023 at 08:02):
ahh lol
Mario Carneiro (Feb 11 2023 at 08:03):
regarding what the unsafety here specifically is, we are trusting (1) that the type String
corresponds to the expression .const ``String []
and (2) the environment at run time is at least an extension of the environment at compile time, so that it makes sense to trust that the types of things in the environment have something to do with the compiled functions also in the environment that we will be calling
Mario Carneiro (Feb 11 2023 at 08:04):
(1) is relatively easy to check locally and to some extent can be automated by a macro
Mario Carneiro (Feb 11 2023 at 08:05):
(2) is almost always the case unless you are running mathlib tactics in the context of a standalone executable with a def main
which calls importModulesConst
to get access to an environment, not necessarily related to the one that was used to compile the program
Mario Carneiro (Feb 11 2023 at 08:07):
basically unsafe
in lean means something similar to unsafe
in rust: it is an unchecked proof obligation of the programmer, such that the consequence of violating the preconditions are usually UB (undefined behavior)
Mario Carneiro (Feb 11 2023 at 08:09):
Of course since lean has a proof language we try to put these proof obligations as literal proof obligations where possible, but they aren't always expressible in the language of lean, if for example they involve interaction with lean runtime representations or other things not visible to the logic
Thomas Murrills (Feb 11 2023 at 08:11):
ohhkay, cool, that's really informative, thx—prior to that explanation unsafe
just seemed like a black box that sometimes exploded. now I can see the kind of things that can make it explode! is that a totally exhaustive list?
Mario Carneiro (Feb 11 2023 at 08:58):
that's the list of things that can make evalTerm
specifically explode
Mario Carneiro (Feb 11 2023 at 08:58):
every unsafe declaration has its own preconditions/postconditions for sound usage
Thomas Murrills (Feb 11 2023 at 10:14):
(deleted)
David Renshaw (Feb 11 2023 at 13:02):
can unsafe
cause Lean to accept an unsound proof?
Mario Carneiro (Feb 11 2023 at 13:02):
yes, easily
Mario Carneiro (Feb 11 2023 at 13:02):
unsafe def foo : False := foo
Mario Carneiro (Feb 11 2023 at 13:03):
well, unsafe
functions are taint-tracked by the kernel so you can't use them to prove things about non-unsafe
Last updated: Dec 20 2023 at 11:08 UTC