-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A new implementation in Lean 4 #672
base: master
Are you sure you want to change the base?
Conversation
You'll need to add a Dockerfile and add the implementation to The inability to mutate environments may not allow it to pass all tests including self-hosting. For particularly interesting implementations, I've waived the self-host requirement before (and Lean might fit that, not sure yet), but it will need to pass all the non-self-hosting tests at least. If it can't pass the non-self-hosted tests then I'll be happy to link to this in the "Other Implementations" section of the README. There are some extra tests that specifically test env mutation that are not in the base set of tests yet but probably will be soon (because this issue is detected in self-host tests but should be detected earlier):
Regarding the eval issue, it's preferred but it's not strictly required that the eval function wrap the outer REPL environment. Closing over the current lexical scope env is also acceptable. The guide indicates the former, but I don't think there are any tests that enforce that and for the time being a suggestion rather than requirement. |
- also remove Mathlib, as it is not used
I added the Dockerfile. Regarding
I tested this and introduced a small change where the new env returned by
Non-optional step 6 tests:
So, I am going to try the idea from my first post and bubble up variables defined with |
I don't understand why this test is not passing.
|
That's so that you can use mal implementations as a scripting language (and pipe results into other commands for example). Being able to print exactly what the script wants to print is important. The script can print the return value explicitly if it wants, but it should be able to avoid printing that too. So when a mal is invoked to load/run another command the final return value needs to be swallowed. |
Status: I now have a more general/correct handling of scopes:
I expected all non-optional tests to pass, but I still have an issue with exiting the process for this test:
Even though mal/impls/lean/LeanMal/step6_file.lean Lines 277 to 283 in fcdd7e5
|
I don't know why the exit doesn't immediately exit (although if it's monadic, maybe control flow needs to unroll to the top-level before the action takes effect? It doesn't look like the code after the else statement is indented. Is the "else" statement in lean 4 indent sensitive? If not maybe you need a do after the else so that the repl code isn't executed? Just stabbing in the dark here. Maybe another option would be moving the donext up and then setting it to false in the args > 2 case? |
fix running with cli args fix step8 macro
The above issue was at the last The more complex implementation with env levels brought an issue with tail call optimization. I tried to fix it in https://github.com/loredanacirstea/mal/tree/lean4-TCO, trying to make
For this Unfortunately, I don't have more time now to work on this PR. |
A new Mal implementation in https://github.com/leanprover/lean4
Except
eval
related tests from step 6, all non-optional tests pass. Due to Lean's restrictions on types, I was not able to implementeval
in a satisfactory way.The Mal version at commit loredanacirstea@562f84e is provable by Lean standards - it does not contain IO side effects (reading files, IO printing). It solves logs by keeping them in the environment instance and forwarding them along, only printing them at the end. There are no mutable elements.
The
Env
instances are not recursive, but I found a way to merge environments and assign each environment and variable a level index. Root has a0
index, which increases each time a new environment is created withfn*
orlet*
. When I merge two environments, I choose the variable with a higher level. And I make sure to bubble up any atoms defined in lower-level environments, in case they were changed.To implement the full guide, I had to change and introduce the IO monad for files, printing logs, and throwing errors, which simplified the code, but we lost proving abilities.
Regarding
eval
: it needs access to the root Env instance, which is usually passed by reference in other implementations. I tried to have a recursiveEnv
here https://github.com/loredanacirstea/mal/blob/lean4-env-ioref-recursive/impls/lean/LeanMal/types.lean#L59, but the prover complained that it does not have a full understanding of all the types, due to the cyclic definition (Types
<->Fun
<->Env
...) . Lean has themutual
block that supports cyclic definitions only for inductive types (likeTypes
,Dict
), not for types usingIO.Ref
(required for passing by reference).A functional, immutable way to implement
eval
may be to bubble up any variables with a low level index inEnv
(eval
should set variables with level index 0), similar to what I did for atoms.