I think your argument makes sense but your example made me think of
something else:

g.V().hasLabel('person').values('age').fold().where(all(gt(18)))

the design of all() is to return true or false. if that's the case then
using it in a where() will always be successful. returning true/false is
really the job of a P so far and this would introduce something new. this
direction could make sense if you wanted this:

g.V().group().by('classroom').by(values('age').fold().all(gt(18))))

where you were trying to set the value of true/false to each "classroom"
being over age 18. i'm not sure that's what we want all() to be doing
exactly. i think it's intention is more like the one you supplied and i
think it was meant more as a specialized filtering step, specialized in
that it worked on List sorts of types only and more like the intention of
the examples you used, as in:

gremlin> g.V().hasLabel('person').values('age').fold().all(gt(18))
==>[29,27,32,35]

In this way, all()/any()/some() is a bit like how is() behaves in that it
can apply a predicate to an item in the traversal stream. A good use case
might be for dealing with results like:

gremlin>
g.V().both().both().group().by('name').by(outE().values('weight').fold()).unfold()
==>ripple=[]
==>peter=[0.2, 0.2, 0.2]
==>vadas=[]
==>josh=[1.0, 1.0, 1.0, 0.4, 0.4, 0.4, 1.0, 1.0, 1.0, 0.4, 0.4, 0.4, 1.0,
0.4]
==>lop=[]
==>marko=[0.4, 0.4, 0.4, 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 0.4, 0.5, 1.0, 0.4,
0.4, 0.4, 0.5, 0.5, 0.5, 1.0, 1.0, 1.0]

where you dont even need to fold() the result. given the results above, i
think folks might want to "find all key/value pairs where all weight values
are gt(0.3)":

g.V().both().both().group().by('name').by(outE().values('weight').fold()).unfold().
  where(select(values).all(gt(0.3)))

i think the analogous form today without all() would maybe be something
like:

gremlin>
g.V().both().both().group().by('name').by(outE().values('weight').fold()).unfold().
......1>   filter(select(values).
......2>          and(count(local).is(gt(0)),
......3>              unfold().choose(__.is(gt(0.3)), constant(1),
constant(0)).
......4>              fold().
......5>              union(sum(local), count(local)).fold().as('x').
......6>
 where('x',eq('x')).by(limit(local,1)).by(tail(local,1))))
==>josh=[1.0, 1.0, 1.0, 0.4, 0.4, 0.4, 1.0, 1.0, 1.0, 0.4, 0.4, 0.4, 1.0,
0.4]
==>marko=[0.4, 0.4, 0.4, 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 0.4, 0.5, 1.0, 0.4,
0.4, 0.4, 0.5, 0.5, 0.5, 1.0, 1.0, 1.0]

so, i think all() in this form does make good sense. it seems less of a
type of P which would imply some sort of fold(), (i.e. stream consumption -
has('weight',all(0.3))) into it which i think would complicate other forms
that take P. making it more like an is() that is designed to work on a List
seems best. i also don't think all() should do too much magic and force
folks to fold() if they don't already have a List sort of type. That said,
I'd be curious how you define all() to behave when it doesn't get that type
or the List type is empty. I assume it would filter in those cases since
that fits the current design direction made in other steps going back to
mid-3.5.x releases.




On Fri, Aug 4, 2023 at 9:29 PM Ken Hu <k...@bitquilltech.com.invalid> wrote:

> Hi All,
>
> As I continue to take a further look into the list functions described in
> Proposal 3, I noticed that they don't take in a Scope. Yet, it could have
> been added because there are some functions that make sense as
> ReducingBarriers. There are some instances, however, where the global scope
> makes no sense so I would propose that we implement these as stated in
> Proposal 3. I just want to point out that this would likely be the first
> time local scope was used as a default for a Step (that isn't unfold) and
> would like to give an opportunity for someone to voice their concerns about
> this.
>
> Let's take a look at one of the examples from Proposal 3.
>
> List Example 1 (LE1)
> Given a list of people, return the list of ages if everyone’s age > 18
> g.V().hasLabel('person').values('age').fold().where(all(gt(18)))
>
> Let's assume the proposal should have included this usage for all() that
> takes a predicate as a parameter. If we remove the fold() from the above
> example so that the example becomes
>
> g.V().hasLabel('person').values('age').where(all(gt(18)))
>
> If all() were to behave like a global scope step here then it would be
> pretty meaningless as the incoming traverser is not a list type. In fact
> the three proposed Steps that return boolean (all, any, none) shouldn't be
> used unless the incoming traverser is an iterable type. In addition, the
> set operations (intersect, union, disjunct and difference) also require the
> incoming traverser to be a list/array type for them to have any sort of
> meaning. I think it's reasonable for the default behavior of all the
> proposed list functions to be the local scope versions. The concat() string
> function has already set a precedent of not taking Scope as a parameter as
> it currently only supports the global scope. In this case, for list
> functions, we would only support local scope. If the user needs global
> scope functionality then they would just need to add a fold() to their
> query.
>
> Does anyone have objections to allowing this to become the default behavior
> for these Steps?
>
> Thanks,
> Ken
>

Reply via email to