-
-
Notifications
You must be signed in to change notification settings - Fork 65
Form refactor #588
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
Draft
rocky
wants to merge
5
commits into
master
Choose a base branch
from
Form-refactor
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Form refactor #588
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
633e8c8
Sketch to showing how to drive Box from Form
rocky e8b20b2
Merge branch 'master' into Form-refactor
mmatera d4a9801
Merge branch 'master' into Form-refactor
mmatera 25e90e6
Merge branch 'master' into Form-refactor
mmatera 8cf2d31
Merge branch 'master' into Form-refactor
mmatera File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| """ | ||
| Example to show how new Format-directed Boxing might work. | ||
|
|
||
| This is a minimal example so we can discuss feasiblity. | ||
| """ | ||
| from mathics.builtin.forms.base import box | ||
| from mathics.core.atoms import IntegerM1, Integer1, Integer2, Rational | ||
| from mathics.core.expression import Expression | ||
| from mathics.core.parser import parse, MathicsSingleLineFeeder | ||
| from mathics.core.symbols import SymbolDivide | ||
| from mathics.core.systemsymbols import ( | ||
| SymbolFractionBox, | ||
| SymbolMakeBoxes, | ||
| SymbolPower, | ||
| SymbolSqrt, | ||
| SymbolStandardForm, | ||
| ) | ||
| from mathics.session import MathicsSession | ||
|
|
||
| session = MathicsSession(character_encoding="ASCII") | ||
|
|
||
|
|
||
| # Hacky pseudo boxing rules. | ||
| # Currently in MakeBox rule rewriting occurs via MakeBox rewrite rules | ||
| # which are attached to various Builtin classes. | ||
|
|
||
| # The rewrite is performed as a part of rewriting portion of Expression evaluation. | ||
| # We probably want to segregate these rules from other kinds of rules. | ||
| # | ||
| # The below hacky code is to simulate the rule behavior for | ||
| # just a few kinds of things so we don't have to hook into the | ||
| # complex rewrite mechanism in use in general evaluation. The implementation we use | ||
| # is just good enough for the new kinds of things we need. | ||
| # It is not intended to be used in a final implementation. | ||
|
|
||
|
|
||
| def fractionbox_fn(expr): | ||
| # To be continued... | ||
| return Expression(SymbolFractionBox, *expr.elements) | ||
|
|
||
|
|
||
| def sqrtbox_fn(expr): | ||
| return Expression(SymbolSqrt, expr.elements[0]) | ||
|
|
||
|
|
||
| def powerbox_fn(expr): | ||
| new_expr = expr.elements[0] | ||
| if new_expr.elements[-1] == IntegerM1: | ||
| return Expression(SymbolDivide, Integer1, new_expr.elements[0]) | ||
| elif new_expr.elements[-1] in (Rational(1, 2), Integer1 * (Integer2**IntegerM1)): | ||
| return Expression(SymbolSqrt, new_expr.elements[0]) | ||
| return new_expr | ||
|
|
||
|
|
||
| boxform_rules = { | ||
| # SymbolTimes: fractionbox_fn, | ||
| SymbolPower: powerbox_fn, | ||
| SymbolSqrt: sqrtbox_fn, | ||
| } | ||
|
|
||
|
|
||
| def apply_formatvalues_rules(expr, evaluation): | ||
| """ | ||
| Hacky replacement for rules() found in Expression rewrite_apply_eval(). | ||
| Note, we need to add builtin FormatValues() and the internals that go with that. | ||
| """ | ||
| if expr.elements[-1] not in (SymbolStandardForm,): # Or more generally $BoxForms | ||
| # For other forms, there might be other transformations too, and this should | ||
| # be discussed. | ||
| # For simplicity, we will just handle a small number of $BoxForms rules | ||
| return expr | ||
|
|
||
| # Remove the Form from expression "expr" | ||
| unboxed_expr = expr.elements[0] | ||
|
|
||
| if unboxed_expr.head in boxform_rules: | ||
| new_expr = boxform_rules[unboxed_expr.head](expr) | ||
| return new_expr | ||
| return unboxed_expr | ||
|
|
||
|
|
||
| # Begin demo code. | ||
|
|
||
| for expr_str in ( | ||
| # FIXME; | ||
| # "1 / x", # Show off "Division" boxing | ||
| "a ^ b", # Show off "Power" boxing | ||
| "Sqrt[a]", # "Square-root boxing" | ||
| "a ^ (1/2)", # "Square-root boxing" | ||
| ): | ||
| print("expression: ", expr_str) | ||
|
|
||
| # Parse, but don't evaluate expression. | ||
| expr = parse(session.definitions, MathicsSingleLineFeeder(expr_str)) | ||
| print("Parsed expression: ", expr) | ||
|
|
||
| # Here is how Mathics currently evaluates MakeBoxes | ||
| boxed_expr = Expression(SymbolMakeBoxes, expr, SymbolStandardForm) | ||
| print("Mathics MakeBoxes: ", boxed_expr) | ||
|
|
||
| # Evaluate to get final printed/rendered form | ||
| print("Eval'd Makeboxes: ", boxed_expr.evaluate(session.evaluation)) | ||
|
|
||
| # Here is how Mathics might better box an expression. | ||
| # First we apply MakeBox boxing transformation rules. | ||
| # This handles expression rewriting. | ||
| transformed_boxed_expr = apply_formatvalues_rules(boxed_expr, session.evaluation) | ||
|
|
||
| boxed_expr2 = box(transformed_boxed_expr, session.evaluation, SymbolStandardForm) | ||
| print("New MakeBoxes: ", boxed_expr2) | ||
| print("-" * 30) | ||
| print("") |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
There is something that I am not seeing in this mechanism: Suppose that we set inside a session a makeboxes rule. Let's say
MakeBoxesfind this rule?Uh oh!
There was an error while loading. Please reload this page.
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.
I am glad you asked this question. Let me direct or attention to this comment in the demo program.
This code is a sketch. It does not change MakeBoxes. Instead the goal was to give an organization where boxing, and later, formatting decisions have no notion of the form that they are embedded in.
It is possible and possibly likely that instead of doing this in methods it needs to be done as rules. In that case, instead of the
box_divide(),box_power()methods insidemathics.builtin.forms.default_boxing, there would be rules instead. Or maybe this could be totally written asdefault_boxing_rules.mand autoloaded.Here is a challenge for you if you are up for it...
Using
MakeExpression,MakeBoxesandFormat, write a new form likeMMateraFormin WL code. It would simulate one of the non-trivial forms likeStandardForm.You are free to "cheat" (actually, you are encouraged to) and use rules from
FormatValuesor any information that a WL implementation will tell you.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.
OK, I saw that. What I was trying to ask about is how you are envisioning that this could work.
OK, I could provide you with some examples of that.
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.
One other I hope small request here. Please start out with simple rules and Forms that lead to simplicity. There is this tendency to lead off with complicated and convoluted edge-case examples involving features we don't currently support in Mathics. And then we go down a rabbit hole focusing on this which doesn't change the base situation.
Instead, it would be awesome if we could start out with simple rules or Forms mimics that cover the majority of the common cases.
This is not to say that we won't get to the complicated and convoluted cases, just that we might do that later after we have some simple mastery of doing things more closely as it is done in Mathematica. (In general, I'd say this is a good thing to practice doing anyway.)