Skip to content
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

Implementation of meta_attribute/2 #40

Open
TeamSPoon opened this issue Jan 4, 2016 · 10 comments
Open

Implementation of meta_attribute/2 #40

TeamSPoon opened this issue Jan 4, 2016 · 10 comments
Labels

Comments

@TeamSPoon
Copy link

This predicate is used to declare a variable attribute and/or the corresponding handlers. The Name is usually the name of module where this attribute is being defined and used. The unqualified use of attributed variables, i.e. terms in the form Var{Attr} is allowed only in modules which have a defined attribute name, otherwise the qualified usage Var{Name:Attr} is required.
The Handlers argument specifies a list of handler predicates for several built-in operations which require user-defined actions whenever an attributed variable is encountered. The list contains elements in the form Operation:Pred, where Operation is the predefined name of the built-in operation and Pred is the handler predicate specification. The handler definition module is assumed to be the module in which meta_attribute/2 is being called; another module can be specified by using the tool body predicate meta_attribute_body/3. When true/0 is specified as the handler or when no handler for a particular operation is specified, this operation will ignore this extension. If the extension Name already exists, the specified handlers are updated, the non-specified ones remain.

The call meta_attribute(Name, []) can be used as a preliminary declaration of a particular attribute, e.g. to compile a module part before the actual declaration is called, or when processing separate files that belong to a particular module.

Most of the C code for this I already tested out to work ..

Docs at http://eclipseclp.org/doc/bips/kernel/termmanip/meta_attribute-2.html

95% of the O_FLUENT patch was in order to make meta_attribute/2 possible.. I backed that out of the workflow since I didn't want it to slow down verify_attributes/3 workflow

@TeamSPoon
Copy link
Author

I examined ECLiPSe's meta_attribute/2 . Turns out I had already implemented quite a bit of it a couple months ago. A couple notes from other issues #14 (comment)

And the bottem 1/2 of #14 (comment)

#define WHAT_copy_term 5 / eager(copy_term)
#define WHAT_compare 6 / eager(compare)

I was kind of worried it was going to be hard to sell particularly those two features to the team..

Luckily, I found documentation to explain my features! http://eclipseclp.org/doc/userman/umsroot100.html#metahandlers

I know all of this can be done with term_expansions and rewrites. (this doesn't relate to Jan's comments about term_expansions) I am just noting matter how weird or complex we want to get we can surely do it with term/goal expansions alone! ) Here is the most commonly known examples of such

:- constraints leq/2.
reflexivity  @ leq(X,X) <=> true.
antisymmetry @ leq(X,Y), leq(Y,X) <=> X = Y.
idempotence  @ leq(X,Y) \ leq(X,Y) <=> true.
transitivity @ leq(X,Y), leq(Y,Z) ==> leq(X,Z).

Now click here to see the term expansion https://dtai.cs.kuleuven.be/CHR/CHRrp/leq_optimised.pl
(The punchline is "Hard to tell the difference between madness and genius" )

I remembered a couple prolog impls I had studied about 12 years ago thinking I could have done that in X number of lines from the impl itself easily. (examples Jinni-Prolog, PAIP-Prolog, LarKC, KernelProlog ) I was unsure how easy it'd be in SWI's C. I assumed it wouldn't be. Although I knew SWI's foreign interface in my sleep I had no idea how many places unification was hidden and where wam would throw wrenches in my designs . Turns out the places with unification is "hidden" is between 3-10 (not 166 places like i was afraid of) (though technically in code is much higher i lump those still into the 3-10 since the pinching off points are easily reworkable from it's existing macros.. though thankfully they do not need reworked). How many hidden copy_terms? How many hidden assignments? Still those numbers are reduced by the fact there are lots of macros. EVEN, All these numbers combined are a fraction of the number of the term_expansion meta hackeries required to make Constraint problems work.

Anyways the beginnings of this is started at

https://github.com/logicmoo/swipl-devel/tree/eclipse_c/

I decided that I can write Tarau's fluents systems completely with ECLiPSe's meta_attribute/2 combined verify_attributes/2 (Which allows a variable to remain a variable even after binding with an atom )

@TeamSPoon
Copy link
Author

I decided that I can write Tarau's fluents systems completely with ECLiPSe's meta_attribute/2 combined verify_attributes/2 (Which allows a variable to remain a variable even after binding with an atom.

What I meant is we implemented already (and its in master) attv_unify(-Var, +Value) on page http://xsb.sourceforge.net/shadow_site/manual2/node4.html. (In swi it is $attvar_assign/2
We just dont yet allow "Assignment can be another attvar " yet

@DouglasRMiles
Copy link

Here is the TODO workflow doc I am using
https://github.com/logicmoo/fluentvars/blob/master/prolog/eclipse_attvars.pl
(Different repository)

On Tue, Jan 5, 2016 at 12:51 AM, Douglas R. Miles notifications@github.com
wrote:

I decided that I can write Tarau's fluents systems completely with
ECLiPSe's meta_attribute/2 combined verify_attributes/2 (Which allows a
variable to remain a variable even after binding with an atom.

What I meant is we implemented already (and its in master)
attv_unify(-Var, +Value) on page
http://xsb.sourceforge.net/shadow_site/manual2/node4.html. (In swi it is
$attvar_assign/2
We just dont yet allow "Assignment can be another attvar " yet


Reply to this email directly or view it on GitHub
#40 (comment).

@TeamSPoon
Copy link
Author

Goal, Instead of merely placing the entire attvar into the variable like in do_unify()
We have these 3 FEATURES:

  • I want an attvar hook to be able to copy some attributes onto the plain variable (VAR) turning it into an ATTVAR
    • But do not want to require that all hooks be upgrading all VARs to ATTVARs!
  • Sometimes Hooks can be allowed to place a Nonvar into that VAR
  • Hooks should be able to leave the variable alone. Or place a different VAR inside the original the VAR.

Q Can we already effectively "almost" do some of these things now in master?
A: Yes, but none of 'master's current methods leave the attvar unscathed (It can only done by destroying the attvar and it's identity)

Q: Was that not Markus @triska's ' original concern that lead to the implementation of verify_attributes/3. Didn't we fix that?
A: Having even verify_attributes/3 is 10x better than before. Having this other thing I suggest as well is only 12x better than before (I wish I could claim 100x !)

Yes, we gave Markus visiting time before we euthanized his attvars and also false choice:

  • False Let it live but force backtracking.
  • True Hold a funeral (3rd argument of verify_attributes)
    • Once again faced with no attvar (no identity) unless he created one in an attribute.

Q: Then having verify_attributes/3 creating a tracking/ID for it's returned closure sounds like a good requirement for someone needing attributes after the variable gets unified.
A: Sure, but the entire argument for verify_attributes/3 was based on removing ID requirement.

Q: What if Markus thinks he doesn't need this capability to do what he is doing?
A: He probably doesn't, otherwise he might have requested it.

  • I am suggesting makes labeling/2 easier.
  • It makes the original "strong versions" of dif/2 and domain/2 possible.
    • domain/2 -like and dif/2 -like when unified with a plain VAR can upgrade the plain variable what it will be domained to and/or different from
    • Upon subsequent unifications the newly created attributed variable is bound to one thing (like a number) and the original attavar can be bound to separately at the same time to another thing and be allowed to decide deny or accept those bindings.
    • Both variables continue to be useful and no backtracking or gensym-ing IDs required)

Q: What are the cons?
A: A programmer who is not careful can end up getting more unifications. So to make things easier,
I can made this behavior specific to an attribute they add to the attvar

Q: So all variables have to be searched for this alternate behaviour slowing down the VM?
A: It would have so I had two ways to minimize damage. A flag telling us to scan or not or a "count" of variables who need need it. (usually zero) I can't decide which is better. Are there better choices?

@triska
Copy link
Member

triska commented Jan 20, 2016

Very nice work Douglas!

Before continuing with this, please let us make sure that what we already have is as robust as possible. For example, today I found another issues with verify_attributes/3 (SWI-Prolog/swipl-devel#108), please have a look.

Let us proceed step by step with this, so that regressions remain easier to detect and correct. My next step will be to port the ZDD-based CLP(B) implementation to the new interface.

After that, let us finish, integrate and test the compatibility layer with SICStus Prolog (get_atts/2, put_atts/2). Once this is available, I will try to port the original CLP(Q) implementation by Christian Holzbaur to SWI-Prolog. It should require much less modification now than previously, and I hope to correct some long-standing issues of the current port by this.

And then, we finally have everything in place to proceed to the next stage, which is the further generalization you are describing here. The fact that I have not yet asked for this does not in any way imply that I do not need it ;-) It's only that we should first strive for correctness of the already available building blocks. Otherwise, mistakes will be too hard to find and correct.

@TeamSPoon
Copy link
Author

I have to give credit to @JanWielemaker. Over the past two weeks, he clarified a couple details about the C code that helped me understand a couple pitfalls I too easily walked into. (avoiding creating C stack (that I don't need) to and how to meaningfully walk upon the shifting sands of pointer world using term_t ) So at least now I am better equipped than before for the next round of patches!

As far as I can tell yes this SWI-Prolog/swipl-devel#108 would be helped is that when two attvars unify you (@triska) may want a chance to update both their properties (put_attr). And in the end have both attvars now updated to have a state in which you expected.

An additional question I have not yet been able to answer for myself but has been nagging at me for a few months now (long before we started verify_attributes/3)

Here:

If two attvars are unifying in many cases wouldn't we want to run unification hooks on BOTH attvars rather than the single one in which has been alive longer?

Like me, I saw Jan did some thinking on well and didn't want to decide either (just added a printf say "Unifying two attvars") since the question would only come up if it ever came up.. But it does in a way comes down to the correctness we are starting to talking about now.

@triska
Copy link
Member

triska commented Jan 20, 2016

The point is that after the unification of two variables, only a single variable remains, so it also makes sense that users only have to update the attributes of one of the two variables in the hook. By convention, in verify_attributes/3, it is the second variable whose attributes are updated in the hook and need to be retained after the unification.

When the hook is called, at least semantically, it need not necessarily be the oldest or youngest variable that is the first or second argument, and in fact it makes sense to not even rely on such a property, and not even guarantee or document at the user level the way this is done. At the implementation level, there may be of course good reasons to prefer one way over the other, and for predictable results, it also makes sense to keep it consistent.

At the user level, what matters is: Which variable's attributes are retained after the hook? That needs to be 100% consistent and predictable for users, and by established convention, it must be those of the Value, i.e., the second argument of verify_attributes/3 if both arguments are variables.

@TeamSPoon
Copy link
Author

On Wed, Jan 20, 2016 at 3:27 PM, Markus Triska notifications@github.com
wrote:

The point is that after the unification of two variables, only a single
variable remains, so it also makes sense that users only have to update the
attributes of one of the two variables in the hook. By convention, in
verify_attributes/3, it is the second variable whose attributes are
updated in the hook and need to be retained after the unification.

When the hook is called, at least semantically, it need not necessarily be
the oldest or youngest variable that is the first or second argument, and
in fact it makes sense to not even rely on such a property, and not even
guarantee or document at the user level the way this is done. At the
implementation level, there may be of course good reasons to prefer one way
over the other, and for predictable results, it also makes sense to keep it
consistent.

Technically there is no way to control or predict which variable even will
be younger or older in master. I did try many experiments hoping I
could.. I ended up coming up with a foolproof method of control but placed
this burden to the programmer to "control". Anyways I won't distract with
that now.

At the user level, what matters is: Which variable's attributes are
retained after the hook? That needs to be 100% consistent and
predictable for users, and by established convention, it must be those of
the Value, i.e., the second argument of verify_attributes/3 if both
arguments are variables.

I think in master we can fix this bug at least. 2 line patch coming in
less than an hour to try :)

Still the 2nd bug will remain and maybe it can be chosen to be ignored for
a while:

You have this responsibility to not just verify your attributes on Var but
also to run wakeup hooks on Value which just might manipulate the attributes of
your Var and change the way you intended to run your business.

@TeamSPoon
Copy link
Author

@DouglasRMiles
Copy link

DouglasRMiles commented Jan 21, 2016 via email

TeamSPoon added a commit to TeamSPoon/swipl-devel-unstable that referenced this issue Jan 21, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants