-
Notifications
You must be signed in to change notification settings - Fork 49
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
run_step_by_step in runner #469
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
flat
argument should work the same way it does forMeTTa.run
current_results
provides 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, 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.
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