-
Notifications
You must be signed in to change notification settings - Fork 78
run_step_by_step in runner #469
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
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API usage is correct, but I am unclear on who you envision as the client for run_step_by_step.
What I mean is that it is a lower-level interface than MeTTa.run but a higher-level interface than creating a RunnerState manually. Personally, I don't know if the solution space has enough surface area to require 3 different interfaces. Perhaps we could eliminate the RunnerState object from the Python API in favor of a yielding MeTTa method like you implemented.
If we do decide to go this route, I'd want to make two changes:
- I think the
flatargument should work the same way it does forMeTTa.run current_resultsprovides access to the whole results list, but the yielding design feels like it should provide only the new results each step. So IMO the easy fix would be to add de-duplication logic to Python, but a better fix might be to plumb the incremental results accessor all the way from the Rust core.
Lastly, I think there should be a test. I quickly wrote this (based on the example from Patrick Hammer), but perhaps you have an idea for a test with better coverage.
def test_run_step_by_step(self):
program = '''
(= (TupleCount $tuple) (if (== $tuple ()) 0 (+ 1 (TupleCount (cdr-atom $tuple)))))
(= tup (1 2))
(= tup (3 4 5))
!(match &self (= tup $t) (TupleCount $t))
'''
runner = MeTTa(env_builder=Environment.test_env())
for _state, results in runner.run_step_by_step(program):
pass
self.assertEqual(len(results[0]), 2)
I wouldn't like to eliminate the lower-level |
|
@luketpeterson trace: It's not perfect representation, but it easier to read than RunnerState, for example call here is the same as in metta, it will try to unify variable, Exit means successful unification _5772=1 The same program in metta also @vsbogd |
|
Thanks for explaining that, @noskill. It sounds like some better accessors for RunnerState's internals will go a long way to provide the debug view you are looking for. |
0fea41e to
ee59f1d
Compare
|
My issue with a yielding API is that each step yields the complete set of results, as opposed to the incremental results. So collecting the results into a list will potentially result in many duplicate values in the list. Does my concern make sense, or am I misunderstanding how you intend the API to be used? I totally see the value in better debug information from RunnerState. I filed this #492 to track that separately. Finally, does my comment about the unnecessary code (below) make sense? Or did I misunderstand something? |
python/hyperon/runner.py
Outdated
| state = RunnerState(self, program) | ||
| state.run_step() | ||
| results = state.current_results() | ||
| yield state, results |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
state.is_complete() starts out returning False, so I don't see the need to execute these 3 lines before entering the loop.
This function should behave identically unless program contains no parsable atoms:
def run_step_by_step(self, program):
"""Runs program step by step, yielding state and result"""
state = RunnerState(self, program)
while not state.is_complete():
state.run_step()
results = state.current_results()
yield state, resultsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I didn't realize I didn't submit this last week.
|
@noskill I would like to hold off merging this because some major changes to the RunnerState object are underway. We may end up eliminating the RunnerState object altogether, and replace it with a delegate object that can be used to monitor for updates, interrupt the execution, and get debug information. It looks like the changes will bring the underlying Rust API closer to what you are doing with the yielding Python method. But it's a heavy WIP. |
|
@noskill , I am not sure whether we need to resolve conflicts and merge or cancel it? |
Actually it was me who is holding up this merge. I felt like the runner's API needed some changes to support multi-threading, and this PR got us further from where we need to be. The reason I didn't close it is because I wanted to keep it as a place to track the suggestions for the Python API, and because I didn't have a replacement to offer yet. |
I find running step by step especially useful for studying a new language, even for declarative languages