Zulip Chat Archive
Stream: new members
Topic: Code generation for what is essentially a no-op function
Iurii Zamiatin (Dec 19 2022 at 04:14):
Hi! I am Iurii, new to this Zulip instance. I have a question about runtime representation of Lean types.
As a beginner, I thought a good learning project would be to formalize simple programming language based on untyped lambda calculus. You can see my attempt at https://gist.github.com/RiscInside/6da4a485b83e6e7e55e7398b62005dce.
I use Expr n
as an type for lambda-calculus with de-brujin indices where n
is the highest index of the free variable (Expr 0
represents expression with no free terms). I have a function called Expr.leftExtend
which translates Expr n
to Expr (n + 1)
. This function does not actually do anything with the term - it simply propogates information down the tree.
-- Left-extend `Expr n` to `Expr (n + 1)`
def Expr.leftExtend (e : Expr n) : Expr (n + 1) :=
match e with
| evar m m_lt_n => evar m (Nat.lt_trans m_lt_n (Nat.lt_succ_self n))
| emku _ => emku (n + 1)
| euop u e => euop u (e.leftExtend)
| ebop b e₁ e₂ => ebop b (e₁.leftExtend) (e₂.leftExtend)
| eabs e => eabs (e.leftExtend)
| elet e₁ e₂ => elet (e₁.leftExtend) (e₂.leftExtend)
| ecas e e₁ e₂ => ecas (e.leftExtend) (e₁.leftExtend) (e₂.leftExtend)
| efix e => efix (e.leftExtend)
As I do quite a few left extensions during substitution, I hoped that lean compiler would be able to pick up on the fact that this function is, in fact, a no-op. To check that, I transpiled this lean file to C with lean -c tiny.c Tiny.lean
. It turns out, however, that lean does indeed generate code for this function and it is very much not a no-op
LEAN_EXPORT lean_object* l_Expr_leftExtend(lean_object* x_1, lean_object* x_2) {
_start:
{
switch (lean_obj_tag(x_2)) {
case 0:
{
uint8_t x_3;
x_3 = !lean_is_exclusive(x_2);
if (x_3 == 0)
{
lean_object* x_4; lean_object* x_5; lean_object* x_6;
x_4 = lean_ctor_get(x_2, 0);
lean_dec(x_4);
x_5 = lean_unsigned_to_nat(1u);
// ...
Is there a way to tell lean compiler this function actually does nothing?
Mario Carneiro (Dec 19 2022 at 04:45):
Automatic detection of identity functions like this is on the roadmap but it will probably be a while. To take the code generation into your own hands you can use unsafeCast
and implemented_by
Iurii Zamiatin (Dec 19 2022 at 04:47):
Thanks. WIll I lose the ability to reason about this function?
Mario Carneiro (Dec 19 2022 at 04:47):
unsafe def Expr.leftExtendImpl (e : Expr n) : Expr (n + 1) := unsafeCast e
-- Left-extend `Expr n` to `Expr (n + 1)`
@[implemented_by Expr.leftExtendImpl]
def Expr.leftExtend (e : Expr n) : Expr (n + 1) :=
match e with
...
Mario Carneiro (Dec 19 2022 at 04:47):
nope
Mario Carneiro (Dec 19 2022 at 04:48):
for reasoning purposes is it not different at all
Mario Carneiro (Dec 19 2022 at 04:48):
however it is now up to you to ensure that the unsafe implementation in fact matches the model
Iurii Zamiatin (Dec 19 2022 at 04:48):
Thanks a lot. Is there a GitHub issue tracking implementation of this functionality?
Mario Carneiro (Dec 19 2022 at 04:52):
I don't think there is, but it would be reasonable to open one
Iurii Zamiatin (Dec 19 2022 at 12:01):
I have opened the issue at https://github.com/leanprover/lean4/issues/1972. I believe this thread can now be closed (although I am not sure how to do it :smile:)
Last updated: Dec 20 2023 at 11:08 UTC