-
Notifications
You must be signed in to change notification settings - Fork 52
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
suspend
, i.e. the Secret Master Plan for Fixing All The Things
#1087
Comments
suspend
, *i.e.* the Secret Master Plan for Fixing All The Thingssuspend
, i.e. the Secret Master Plan for Fixing All The Things
Very exciting! Not to derail the topic, but is there any overlap with the concept of |
I don't think they are related, but I could be wrong; maybe there is some more fundamental underlying mechanism. |
Thanks for the detailed write-up @byorgey, I will study it on my 2-hour train journey tomorrow. 😄 On a more serious note, the simplifications sound very promising and I am hopeful this will end our CESK bugs. Afterwards, we should add a way to inspect the CESK machine environment in UI (tweezers) and outside with Web API. |
Instead of getting rid of
Or a similar version of EDIT: a fun idea is to keep |
Just adding a note to say that we (and by we I mean "I") shouldn't let the issues with |
I have started working on this. So far I have deleted a LOT of code (mostly weird special cases), and it makes me so happy. I still have some new code to write as well, but I think overall this will end up being a big net decrease in the number of lines of code. |
…tate (#1928) The big idea of this PR is to add a new type of CESK machine state, `Suspended`, which is a state the base robot automatically goes into after completing execution of a program entered at the REPL. It is as if the base robot is still within the local context of any definitions etc. entered previously, just printed out an "intermediate result", and is now waiting to find out what the next term to be executed will be. This allows us to treat `def` as syntax sugar for `let` and results in a much cleaner way to manage the context of definitions, which in turn allows us to remove a whole lot of special cases and fixes several annoying bugs. See #1087 for more explanation and discussion. Things that are **deleted** (!) by this PR: - `TDef` (`def` is now just syntax sugar for `let`) (#997) - `VResult` (we no longer need to return anything other than plain values) - `FUnionEnv`, `FDiscardEnv`, `FLoadEnv` (we no longer need machinery to collect up definitions while evaluating terms) - `ProcessedTerm` (just a plain `TSyntax` (i.e. `Syntax' Polytype`) is now enough) - `Module` (it only existed to package up some contexts with typechecked terms, but we don't need them anymore) - `RobotContext` and `topContext` (we don't need to store those things separately any more, they are just stored in the `CESK` machine where they belong) Additions/changes: - The `Requirement` module is split into `Requirements.Type` and `Requirements.Analysis` to avoid circular module imports - New `Suspended` state for the CESK machine - `def` and `tydef` are now allowed anywhere (even nested inside other definitions etc.) since `def x = y end; z` is just syntax sugar for `let x = y in z` (see #349) - Code size decreased slightly for many programs using `def`, since `def` is now a synonym for `let`, and consecutive `def`s therefore do not require a `bind`. Closes #1087. Fixes #681 (hence also #736, #1796). Fixes #1032. Closes #1047. Closes #997. Fixes #1900. Fixes #1466. Fixes #1424. See also #636.
The big idea
What happens, theoretically and practically, when you type stuff at the REPL? The way I always think about it is that it's as if you're writing one big long block of commands chained by semicolons; it just so happens that you get to enter them one at a time. This explains why names defined at the REPL should be in scope for later things entered at the REPL. (Well, you can also enter expressions to be evaluated in addition to commands, but this can easily be explained by saying that anything without a command type gets implicitly wrapped in
return
.)So what is the
base
doing in between REPL entries? Currently, it is idle, just like any robot that has finished running its program. But this is wrong! We should have a new CESK machine state to represent what the base is doing while waiting for another REPL input.Fundamentally, the base is doing something different than an idle robot. An idle robot will never do anything more unless another robot comes to
salvage
orreprogram
it. The base will resume executing as soon as something else is entered at the REPL. If only for conceptual reasons it makes sense to distinguish between these states.If the base is idle, its CESK machine no longer remembers any context or store. So we have to save them into the
robotContext
just so we can load them back into the new CESK machine state on the next REPL input. I now realize how silly this is! Why not just have the CESK machine remember it all along?Details
I propose adding a new CESK machine state
Suspended
and a new primitive constantsuspend
.The new machine state could be called
Suspended
, and will contain a resultValue
, a currentEnv
, and a currentStore
. I do not think it needs to have a continuation (since I cannot think when we would ever want anything besides the empty continuation), but we could easily add a continuation if it turns out to be useful later.The new primitive is
suspend : a -> cmd a
.suspend v
is executed, it has the effect of putting the machine immediately into theSuspended
state, withv
as the value, and the current environment and store.suspend
should not be available for players to use, but will only be used internally.x; y; z
is entered at the REPL, it will be automatically rewritten tox; y; v <- z; suspend v
.suspend
comes last, so there will in fact be an empty continuation at the point when it is executed, which is why theSuspended
state does not need to store one.x; suspend v; y
then we would need to save a continuation.Instead of checking to see when the base is idle, the REPL will now check to see when it becomes
Suspended
When something is entered at the REPL, the environment stored in the current
Suspended
machine state will be used to typecheck it, and then theSuspended
state will be replaced with a state appropriate to evaluate/execute the given input (with the environment and store carried over), just as if the originalsuspend v
call had been replaced with the new input. In other words, if you typea; b; c
at the REPL and then later enterx; y; z
, the net effect of thesuspend
is to make it as if you had literally writtena; b; c; x; y; z
.We will need to put some thought into what happens with uncaught exceptions that bubble up to the top level. The current environment and store will have to be captured somehow and put into a
Suspended
state with a unit value. In other words, ifx; y; z
is being executed andy
throws an exception, it should be as ify; z
is replaced bysuspend ()
.This will actually be better than the status quo, which one could argue has a bug: if you execute something like
def m = move end; move
in Classic mode themove
throws an exception (since the base does not havetank treads
), andm
is not added to the context. In other words the entire command fails if any part of it fails; but one could argue that thedef m
should succeed and addm
to the context before going on to try themove
.Implications
There will no longer be any such thing as a "global context", only local scopes managed according to the usual rules. The top-level REPL scope will just be an open-ended "local" scope where each new command is nested within the scope of previous ones.
The only reason we needed all the
VResult
andFLoadEnv
stuff is to collect up exported names so we can stuff them into therobotContext
to save them across times when the base is idle waiting for the next REPL input. That will now just happen automatically.Value
into command and expression values #1047 irrelevant.itN
resulting from a bind #977 and Fatal error withtry
block + bind #327.However, this does mean that any
Env
stored in a CESK machine state will now need to store not just the value of each name but also its type and requirements (because we will may need to typecheck stuff entered at the REPL later). EssentiallyEnv
will becomeRobotContext
.We can also get rid of
FDiscardEnv
, which was only a bandaid created to prevent names leaking via theVResult
machinery.Definitions and import
Now that there is no longer any such thing as a global context, we should seriously reconsider #997. In fact we could simply get rid of
def
and only allowlet ... in
. Or we could makedef x : ty = e end; c2
syntax sugar forlet x : ty = e in c2
. Only havinglet ... in
would be awkward for typing definitions at the REPL since you would have to explicitly saylet x = e in suspend ()
or something like that. But then again having bothlet
and alsodef
which is syntax sugar forlet
would be confusing. Maybe we could have...
as syntax sugar forsuspend ()
so you could writelet x = e in ...
. Or we could just replace thedef
keyword withlet
, that is,let x = e end; c2
would be syntax sugar forlet x = e in c2
(andlet x = e end
by itself would belet x = e in suspend ()
).One difficulty is how to handle imports (#495). All of this makes
run
even more problematic than before. A few ideas:def
is replaced with (or syntax sugar for)let ... in
, the question arises what we should do at the end of a sequence of definitions (say, in a.sw
file). One idea would be to make a sequence ofdef
s syntax sugar for a chain oflet
s with a call tosuspend ()
at the very end.run
with a syntactic constructimport <text_literal> in e
, which would load the contents of the file with the given name and run it, replacing the finalsuspend
withe
. The downside of this idea is there would be a distinction between importing a file of definitions (usingimport ... in ...
) and importing a file containing an expression.open ... in ...
construct to dump all the names in a record into the current scope, so we wouldn't be tied to always having qualified imports. However, checking such a construct seems problematic (see the discussion at Records #1148).The text was updated successfully, but these errors were encountered: