-
-
Notifications
You must be signed in to change notification settings - Fork 76
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
MathObject version of the new Boolean context #1035
Conversation
270ee25
to
ae43664
Compare
ae43664
to
7633a66
Compare
I'd definitely vote for Perl puts |
I wouldn't be opposed, but also not inclined to promote that. If I were picking something other than the words, I'd pick Are the operators case insensitive? If not, it might be good to make |
Note that the The logical operators are I'd recommend (from high to low) If there are different preferences, you might want to have |
Note that you should not mix high and low precedence operators such as |
Note the usual rule of thumb for perl is to only use the low precedence operators (or, and, not) for control flow. Not for logic operations in conditionals. So I don't think those should be considered in this discussion. Instead look at |
It doesn't really matter which set you are looking at, as the relative precedences within the sets are the same, which is all that we are after here. I used My example that mixed them above was an attempt to understand why there are two sets in the first place with different precedences (still a mystery to me), and was probably not worth including, except that I wanted to point out that there are differing opinions on what the meaning of Of course, mathematical conventions can't always be encoded in a precedence-based parser, but how the precedences are set here will determine which interpretation of |
I like the suggestion of a helper method for authors to choose between precedence settings. It seems inevitable that there will be authors on either side. I'm thinking something along the lines of |
Because each MathObject contains a pointer to the context in which it is created, and because Context("Boolean");
Context()->constants->set(T => {string => "True"}); the constant is changed in the copied context, while the original template context is unchanged. But It was probably a bad suggestion on my part to create a global The first step is to define the subclass sub copy {
my $self = shift->SUPER::copy(@_);
## update the T and F constants to refer to this context
$self->constants->set(
T => {value => context::Boolean::Boolean->new($self, 1)},
F => {value => context::Boolean::Boolean->new($self, 0)}
);
return $self;
}
## Access to the constant T and F values
sub F { shift->constants->get('F')->{value} }
sub T { shift->constants->get('T')->{value} }
This You could also add ## top-level access to context-specific T and T
sub T {
my $context = main::Context();
Value::Error("Context must be a Boolean context") unless $context->can('T');
return $context->T;
}
sub F {
my $context = main::Context();
Value::Error("Context must be a Boolean context") unless $context->can('F');
return $context->F;
} to the Then at the end of the ## add our methods to this context
bless $context, 'context::Boolean::Context'; to make your new context be your subclassed one. If you make these changes, then your my $T = $context->T;
my $F = $context->F; to get the return "($result ? context::Boolean->T : context::Boolean->F)"; while return $self->value ? 'context::Boolean->T' : 'context::Boolean->F'; In the same vein, the sub _eval {
my ($self, $l, $r) = @_;
return ($l->value || $r->value ? $self->context->T : $self->context->F);
} with similar changes to the other ones. Finally, the original constants themselves would be added in ## Define constants for 'True' and 'False'
$context->constants->{namePattern} = qr/(?:\w|[\x{22A4}\x{22A5}])+/;
$context->constants->are(
T => {
value => context::Boolean::Boolean->new($context, 1),
string => 'T',
TeX => '\top',
perl => 'context::Boolean->T',
alternatives => ["\x{22A4}"]
},
F => {
value => context::Boolean::Boolean->new($context, 0),
string => 'F',
TeX => '\bot',
perl => 'context::Boolean->F',
alternatives => ["\x{22A5}"]
},
'True' => { alias => 'T' },
'False' => { alias => 'F' },
);
Note the line at the top of the last perl code block above that changes the constants' I had included this in a comment earlier, but it would be easy to miss.
Yeas, that probably wants to be changed. In the meantime, you can subclass ## Subclass Parser::Number to return the constant T or F
package context::Boolean::Number;
our @ISA = ('Parser::Number');
sub eval {
my $self = shift;
return $self->context->constants->get(('F', 'T')[$self->{value}])->{value};
}
sub perl {
my $self = shift;
return $self->context->constants->get(('F', 'T')[$self->{value}])->{perl};
} and add $context->{parser}{Number} = 'context::Boolean::Number'; at the top of the sub _reduce {
my $self = shift;
my $reduce = $self->context->{reduction};
my $l = $self->{lop};
my $r = $self->{rop};
return $self unless ($l->{isConstant} || $r->{isConstant});
if ($l->{isConstant}) {
return $l->eval->value ? ($reduce->{'x||1'} ? $l : $self) : ($reduce->{'x||0'} ? $r : $self);
} else {
return $r->eval->value ? ($reduce->{'x||1'} ? $r : $self) : ($reduce->{'x||0'} ? $l : $self);
}
} (note also the use of
To do that, you can add ## Easy setting of precedence to different types
sub setPrecedence {
my ($self, $order) = @_;
if ($order eq 'equal') {
$self->operators->set(
or => {precedence => 3},
xor => {precedence => 3},
and => {precedence => 3},
not => {precedence => 3},
);
} elsif ($order eq 'oxan') {
$self->operators->set(
or => {precedence => 1},
xor => {precedence => 2},
and => {precedence => 3},
not => {precedence => 6},
);
} else {
Value::Error("Unknown precedence class '%s'", $order);
}
} to the I've added a copy of the context file with the modifications I mentioned (I think I included everything I changed). |
I suggested it because the TeX output looks like these, and you are already using I'm not sure what problem you are anticipating about interference with
That certainly would be a reasonable work-around for now, until the core constant implementation is fixed to include that.
I would say yes, but some checking is probably in order to make sure that there are not unwanted side effects. I can't think of any, but there could be. One result will be that computations using the evaluated result will be slower since they go through the MathObject overloads rather than the direct perl computations. Also, comparisons will be done with the fuzzy tolerance parameters, and that might lead to unexpected results in some cases, particularly comparisons like
No, I would go with the context-specific |
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 thing that is missing from this at this point is POD. But perhaps you are waiting until the code is ready to work on that?
Perhaps 'vee' should be added as an alternate for 'or', 'wedge' an alternate for 'and', and 'oplus' an alternate for 'xor'. Those are the texts that MathQuill outputs when those symbols are entered. So if buttons are added to the toolbar for these logic symbols, then those answers would be considered correct. The alternates could also only be added when MathQuill is enabled. Perhaps the text output of MathQuill could be changed, but I am not sure that is a good idea since those symbols have other meanings in different mathematical contexts.
I noticed something unexpected in testing this. Consider the following minimal example:
DOCUMENT();
loadMacros('PGstandard.pl', 'PGML.pl', 'contextBoolean.pl');
Context('Boolean');
$ans = Formula('not (p or q)');
BEGIN_PGML
Enter [`[$ans]`]: [_]{$ans}
END_PGML
ENDDOCUMENT();
In that example $ans
is displayed as ~p∨q
, yet if you enter not p or q
it is counted as incorrect. It seems that the parentheses should not be removed when this is displayed. This may be related to the precedence or not
and or
.
macros/contexts/contextBoolean.pl
Outdated
## Define our logic operators | ||
# (for now...) | ||
# all binary operators have the same precedence and process left-to-right | ||
# any parens to the right must be preserved with consecutive binary ops |
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.
Please don't use this kind of comment. That is just use a single #
for comments, and don't use the reverse indented style. With syntax highlighting in any modern text editor, there is no need for additional #
s to offset comments. It completely baffles me where this reverse indented comment style comes from.
Preferably comments would be full sentences with punctuation and capitalization.
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.
Thanks, yeah, this will get cleaned up as we decided on precedence options -- and related to your other comment, something with the parens config is off...
Also, regarding POD, you're right, and I was waiting for the dust to settle on some of the pending issues.
I looked into the parens issue with 'not' that @drgrice1 outlined above, and it seems that UOPs do not pass along a 'showParens' argument. As a result, the child BOP ('or' in the example above) does not add parens when the precedences are the same (because Lines 336 to 343 in 5360cb6
Just to confirm with @dpvc, the right move here is to add a |
It looks like I never considered the possibility of a unary operator having the same precedence as binary operators that they may apply to.
I think this may actually be overkill, as I think that if the precedences are the same, you should always use parentheses, so there is no need for a You will also need to do something similar to the For now, you could add sub string {
my ($self, $precedence, $showparens, $position, $outerRight) = @_;
$showparens = "same" if !($position // '') && !($showparens // '');
return $self->SUPER::string($precedence, $showparens, $position, $outerRight);
}
sub TeX {
my ($self, $precedence, $showparens, $position, $outerRight) = @_;
$showparens = "same" if !($position // '') && !($showparens // '');
return $self->SUPER::TeX($precedence, $showparens, $position, $outerRight);
} to the |
macros/contexts/contextBoolean.pl
Outdated
class => 3, | ||
precedence => 1, |
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.
Did you mean to change the class
to 3 and leave the precedence
as 1? I think you may have meant to change the precedence so that implied multiplication is the same precedence as everything else.
That also points out that I forgot to change the precedence of ' '
in the setPrecedence()
method, so you should probably add that in.
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.
Yep, great catch here.
Yeah, that absolutely makes sense. No need to make that configurable. |
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.
This looks ready now.
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 think this looks good at this point. Let us know when you are ready for this to be merged (I think you said you have something else you wanted to do yet).
MathObject version of the new Boolean context
This was actually merged into develop. I added to the PG-2.19 branch as well now. |
Refer to #1033 if you really want to see how this sausage got made. Many thanks to @dpvc, as always.
Here it is! A boolean context for MathObjects.
Features
$context::Boolean::T
and$context::Boolean::F
Unresolved Issues
inContext
each time they appear? (ineval
, even inperl
)Parser::Number::eval
seems to be the only (?) evaluator that doesn't return a MathObject_reduce
methods hereperl
(henceperlFunction
also)still unclear why thisValue::Real
subclass doesn't inheritcmp_defaults
more details -- see item 1Future Steps
cmp_defaults
link -- item 1Feedback Requests
/\
and\/
added as alternatives for 'and' and 'or'?isConstant => 1
? link -- see item 4Parser::Number::eval
return a MathObject (in alignment with other classes'eval
methods)?$context::Boolean::T
(or F) wheneval
ing?