Conversation
…tened. Improve partial-inline of math-dispatch.
…rmined correctly.
Added `bootstrap-word` to `object`.
The specific order of the methods is - First, the hook variables are in the order they were written - Next, stack parameters in order from top side * Disabled checking for generics in covariant-tuple dispatch.
|
I changed the sort order of methods in IN: scratchpad USE: multi-generic
IN: scratchpad
TUPLE: t1 ;
TUPLE: t2 ;
TUPLE: t3 ;
TUPLE: t4 < t1 ;
TUPLE: t5 < t2 ;
TUPLE: t6 < t3 ;
TUPLE: t7 < t4 ;
TUPLE: t8 < t5 ;
MGENERIC: m-nc ( o1 o2 o3 -- no )
MM:: m-nc ( :t1 :object :object -- No.1 ) 1 ;
MM:: m-nc ( :t7 :t5 :object -- No.2 ) 2 ;
MM:: m-nc ( :t4 :object object -- No.3 ) 3 ;
MM:: m-nc ( :object :t8 :t6 -- No.4 ) 4 ;
MM:: m-nc ( :object :object :object -- No.5 ) 5 ;
MM:: m-nc ( :object :t2 :object -- No.6 ) 6 ;
MM:: m-nc ( :object :object :t3 -- No.7 ) 7 ;
MM:: m-nc ( :t4 :t5 :t6 -- No.8 ) 8 ;
MM:: m-nc ( :object :t5 :object -- No.9 ) 9 ;IN: scratchpad \ m-nc methods sort-methods [ second ] map .
{
MM\ m-nc ( :object :t8 :t6 -- No.4 )
MM\ m-nc ( :t4 :t5 :t6 -- No.8 )
MM\ m-nc ( :object :object :t3 -- No.7 )
MM\ m-nc ( :t7 :t5 :object -- No.2 )
MM\ m-nc ( :object :t5 :object -- No.9 )
MM\ m-nc ( :object :t2 :object -- No.6 )
MM\ m-nc ( :t4 :object object -- No.3 )
MM\ m-nc ( :t1 :object :object -- No.1 )
MM\ m-nc ( :object :object :object -- No.5 )
}Sorting with MGENERIC: m-c ( o1 o2 o3 -- no ) cached-multi
MM:: m-c ( :t1 :object :object -- NO.1 ) 1 ;
MM:: m-c ( :t7 :t5 :object -- No.2 ) 2 ;
MM:: m-c ( :t4 :object object -- No.3 ) 3 ;
MM:: m-c ( :object :t8 :t6 -- No.4 ) 4 ;
MM:: m-c ( :object :object :object -- No.5 ) 5 ;
MM:: m-c ( :object :t2 :object -- No.6 ) 6 ;
MM:: m-c ( :object :object :t3 -- No.7 ) 7 ;
MM:: m-c ( :t4 :t5 :t6 -- No.8 ) 8 ;
MM:: m-c ( :object :t5 :object -- No.9 ) 9 ;IN: scratchpad \ m-c "dispatch-type" word-prop methods>> sort-single-methods [ second ] map .
{
MM\ m-c ( :object :object :object -- No.5 )
MM\ m-c ( :t1 :object :object -- NO.1 )
MM\ m-c ( :t4 :object object -- No.3 )
MM\ m-c ( :object :t2 :object -- No.6 )
MM\ m-c ( :object :t5 :object -- No.9 )
MM\ m-c ( :t7 :t5 :object -- No.2 )
MM\ m-c ( :object :object :t3 -- No.7 )
MM\ m-c ( :t4 :t5 :t6 -- No.8 )
MM\ m-c ( :object :t8 :t6 -- No.4 )
}They are the same in that they are focused on the specificity of the top of the stack, but the order is reversed. |
|
Is this changing the order of dispatch? Or is this an implementation detail of what order it checks the stack arguments?
… On Mar 4, 2021, at 5:42 AM, kusumotonorio ***@***.***> wrote:
I changed the sort order of methods in multi-generic to be different from multi-methods.
IN: scratchpad USE: multi-generic
IN: scratchpad
TUPLE: t1 ;
TUPLE: t2 ;
TUPLE: t3 ;
TUPLE: t4 < t1 ;
TUPLE: t5 < t2 ;
TUPLE: t6 < t3 ;
TUPLE: t7 < t4 ;
TUPLE: t8 < t5 ;
MGENERIC: m-nc ( o1 o2 o3 -- no )
MM:: m-nc ( :t1 :object :object -- No.1 ) 1 ;
MM:: m-nc ( :t7 :t5 :object -- No.2 ) 2 ;
MM:: m-nc ( :t4 :object object -- No.3 ) 3 ;
MM:: m-nc ( :object :t8 :t6 -- No.4 ) 4 ;
MM:: m-nc ( :object :object :object -- No.5 ) 5 ;
MM:: m-nc ( :object :t2 :object -- No.6 ) 6 ;
MM:: m-nc ( :object :object :t3 -- No.7 ) 7 ;
MM:: m-nc ( :t4 :t5 :t6 -- No.8 ) 8 ;
MM:: m-nc ( :object :t5 :object -- No.9 ) 9 ;
IN: scratchpad \ m-nc methods sort-methods [ second ] map .
{
MM\ m-nc ( :object :t8 :t6 -- No.4 )
MM\ m-nc ( :t4 :t5 :t6 -- No.8 )
MM\ m-nc ( :object :object :t3 -- No.7 )
MM\ m-nc ( :t7 :t5 :object -- No.2 )
MM\ m-nc ( :object :t5 :object -- No.9 )
MM\ m-nc ( :object :t2 :object -- No.6 )
MM\ m-nc ( :t4 :object object -- No.3 )
MM\ m-nc ( :t1 :object :object -- No.1 )
MM\ m-nc ( :object :object :object -- No.5 )
}
Sorting with sort-single-methods (equivalent to sort-methods in generic) whitch uses <=> in covariant-tuple dispatch looks like this:
MGENERIC: m-c ( o1 o2 o3 -- no ) cached-multi
MM:: m-c ( :t1 :object :object -- NO.1 ) 1 ;
MM:: m-c ( :t7 :t5 :object -- No.2 ) 2 ;
MM:: m-c ( :t4 :object object -- No.3 ) 3 ;
MM:: m-c ( :object :t8 :t6 -- No.4 ) 4 ;
MM:: m-c ( :object :object :object -- No.5 ) 5 ;
MM:: m-c ( :object :t2 :object -- No.6 ) 6 ;
MM:: m-c ( :object :object :t3 -- No.7 ) 7 ;
MM:: m-c ( :t4 :t5 :t6 -- No.8 ) 8 ;
MM:: m-c ( :object :t5 :object -- No.9 ) 9 ;
IN: scratchpad \ m-c "dispatch-type" word-prop methods>> sort-single-methods [ second ] map .
{
MM\ m-c ( :object :object :object -- No.5 )
MM\ m-c ( :t1 :object :object -- NO.1 )
MM\ m-c ( :t4 :object object -- No.3 )
MM\ m-c ( :object :t2 :object -- No.6 )
MM\ m-c ( :object :t5 :object -- No.9 )
MM\ m-c ( :t7 :t5 :object -- No.2 )
MM\ m-c ( :object :object :t3 -- No.7 )
MM\ m-c ( :t4 :t5 :t6 -- No.8 )
MM\ m-c ( :object :t8 :t6 -- No.4 )
}
They are the same in that they are focused on the specificity of the top of the stack, but the order is reversed.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
|
Since the method is checked for conformity in the sorted order, how it is sorted may be important for execution. For example, let's define a set of generics and methods like the above in IN: scratchpad t1 new t5 new t6 new m-nc .
7In Next, we will see if this is the case with IN: scratchpad t1 new t5 new t6 new mm .
1It chose the method |
|
Is that eventually resolved via call-next-multi-method?
Meaning is it a question of ordering, or is one preventing the other from being called?
… On Mar 4, 2021, at 3:30 PM, kusumotonorio ***@***.***> wrote:
Since the method is checked for conformity in the sorted order, how it is sorted may be important for execution.
For example, let's define a set of generics and methods like the above in multi-generic and multi-methods, and put t1, t5, and t6 tuples on the stack to call those generics.
IN: scratchpad t1 new t5 new t6 new m-nc .
7
In multi-generic, the method that returns 7, MM\ m-c ( :object :object :t3 -- No.7 ), was chosen. It is the third from the top in the sort order. Since t6 is a subclass of t3 and is at the top of the stack, it was given more weight in the choice of methods.
Next, we will see if this is the case with multi-methods.
t1 new t5 new t6 new mm .
1
It chose the method mm-{ t1 object object }, which returns 1.
It is the fourth method in the multi-methods. The emphasis here is on t1, which is the deepest in the stack.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
What exactly do you mean by this? I believe that the choice of methods from either side of the stack is a matter of "specification promise", not "semantic certainty". Once that rule is set, it shouldn't matter which way we go, but we need to be consistent. |
|
I noticed that the function I implemented in I made it to mimic the When I imagine the situation where http://web.mit.edu/r/current/lib/R/library/methods/html/NextMethod.html
It seems that R's it has a similar character to my implementation. I'm trying to figure out what I should do. Here's what I came up with.
Which one do you think is the best? |
|
@timor I noticed that the cache dispatch of covariant-tuple does not make the correct method selection in What was happening before this change was that the default method was chosen at any time. In the rock-paper-scissors test, the result was always a loss. |
Yes, I noticed that and that should be fixed in the current branch.
Can you give an example which currently fails? |
|
I have previously made changes based on your changes timor@3c0c6ed and timor@cee950d . The one that disabled those changes passes the following test. MGENERIC: cached-md-beats? ( obj1 obj2 -- ? ) cached-multi
MM:: cached-md-beats? ( obj1: paper obj2: scissors -- ?: boolean ) obj1 obj2 2drop t ;
MM:: cached-md-beats? ( :scissors :rock -- ?: boolean ) t ;
MM:: cached-md-beats? ( :rock :paper -- ?: boolean ) t ;
MM:: cached-md-beats? ( :thing :thing -- ?: boolean ) f ;
{ f t f f f t t f f } [
paper paper cached-md-beats?
paper scissors cached-md-beats?
paper rock cached-md-beats?
scissors paper cached-md-beats?
scissors scissors cached-md-beats?
scissors rock cached-md-beats?
rock paper cached-md-beats?
rock scissors cached-md-beats?
rock rock cached-md-beats?
] unit-testEnabling these changes does not give the expected result. resource:extra/multi-generic/multi-generic-tests.factor: 233
Unit Test: {
{ f t f f f t t f f }
[
paper paper cached-md-beats?
paper scissors cached-md-beats?
paper rock cached-md-beats?
scissors paper cached-md-beats?
scissors scissors cached-md-beats?
scissors rock cached-md-beats?
rock paper cached-md-beats?
rock scissors cached-md-beats?
rock rock cached-md-beats?
]
}
=== Expected:
f
t
f
f
f
t
t
f
f
=== Got:
f
f
f
f
f
f
f
f
fI left |
|
@kusumotonorio It seems to work correctly with my latest code. Can you point me to a commit that I can check out to reproduce the problem? |
|
@timor |
Oh sorry, that was not what I meant with "my latest code", I was referring to the other PR (#2430). If you point me to a commit to check out, I am happy to take a look at what could be the difference. |
|
I have always wanted to run your PR under myself, and have tried several times, but unfortunately have not yet succeeded in doing so. |
Right now, the method selection priority of (defclass t0 () ())
(defclass t1 (t0) ())
(defclass t2 (t1) ())
(defclass t3 (t2) ())
(defmethod m-cl ((c1 t3) (c2 t0) (c3 t2)) (format t "No.1-") (call-next-method))
(defmethod m-cl ((c1 t2) (c2 t2) (c3 t2)) (format t "No.2-") (call-next-method))
(defmethod m-cl ((c1 t2) (c2 t0) (c3 t0)) (format t "No.3-") (call-next-method))
(defmethod m-cl ((c1 t0) (c2 t0) (c3 t0)) (format t "No.4~%"))
* (m-cl (make-instance 't3) (make-instance 't2) (make-instance 't0))
No.3-No.4
NIL
* (m-cl (make-instance 't2) (make-instance 't2) (make-instance 't2))
No.2-No.3-No.4
NIL
* (m-cl (make-instance 't3) (make-instance 't2) (make-instance 't2))
No.1-No.2-No.3-No.4
NILUSE: multi-generic
TUPLE: t0 ;
TUPLE: t1 < t0 ;
TUPLE: t2 < t1 ;
TUPLE: t3 < t2 ;
MGENERIC: mg ( o1 o2 o3 -- )
MM: mg ( :t3 :t0 :t2 -- ) "No.1-" write call-next-multi-method ;
MM: mg ( :t2 :t2 :t2 -- ) "No.2-" write call-next-multi-method ;
MM: mg ( :t2 :t0 :t0 -- ) "No.3-" write call-next-multi-method ;
MM: mg ( :t0 :t0 :t0 -- ) 3drop "No.4" write nl ;
IN: scratchpad t3 new t2 new t0 new mg
No.3-No.4
IN: scratchpad t2 new t2 new t2 new mg
No.2-No.3-No.4
IN: scratchpad t3 new t2 new t2 new mg
No.1-No.3-No.4In the last example of |
|
@kusumotonorio Wow, that's really interesting! I always thought that Factor and CLOS have the same semantics there. The documentation of
It seems that CLOS computes the precedence order of all applicable methods at the first call site, based on the present argument classes. Factor does not do that, since it does not have the information of what the generic function was called with when dispatching again in a nested |
|
I just checked the behavior with my covariant tuple branch. This is one of the cases where the dispatch is ambiguous. A compiler "warning" error is generated after defining all methods: |
I think you're right. |
|
In The Common Lisp Cookbook,
If we take the phrase "the next most specific method" to mean "the method with the next most specific specializer for the current method's specializer", we can use |
|
The current version of I need to understand what I have to do when I redefine a Factor word, but since |
Can you give an example of what the problematic behavior is? |
|
@timor Thank you for your interest. I will answer with a better idea of what the problem is. Please give me some time. |
| M: anonymous-complement (classes-intersect?) | ||
| class>> class<= not ; | ||
|
|
||
| : 2any? ( ... seq1 seq2 quot: ( ... elt1 elt2 -- ... ? ) -- ... ? ) |
| ! exclusive. | ||
| M: covariant-tuple (classes-intersect?) | ||
| covariant-classes | ||
| [ classes-intersect? ] 2all? ; |
This is one of the implementations that adds multi-methods to Factor.
This is an extension of the already existing
multi-methods. In addition, it includes thegenericfunctionality.It declares methods with a unified syntax for generic words that dispatch with a single stack parameter, dispatch with a single hook variable, mathematical double-dispatch, and dispatch with a combination of stack parameters and hook variables.
Basic syntax
Multi-dispatchable generic word declaration
Dispatching by hook variables is optional. When not in use, hook variables and the partition
|are not written.To declare a mathematical generic word equivalent to the one declared by
MATH:, writemathematical.example:
Defining methods for multi-dispatch support
Local variables can be used in the definition by
MM::.Literal representation of multi-dispatchable methods
MM\ foo ( hookvar1: hv1-class hookvar2: vh2-class ... | in1: in1-class-c in2: in2-class-d ... -- out11 out2 ... )Example
Other features include
generic, so their execution speed is expected to be the same.call-next-multi-methodcan be used to allow differential programming through class inheritance.typedfeature guarantees the class of the output and adds optimization information.