Can you introspect predicate arity and if it's an equality predicate?

aliak something at something.com
Fri Jan 12 13:01:30 UTC 2018


On Friday, 12 January 2018 at 08:18:02 UTC, Simen Kjærås wrote:
> On Friday, 12 January 2018 at 00:16:07 UTC, aliak wrote:
>> Hi, so basically is there a way to:
>>
>> void func(alias pred = null, Range)(Range range) {
>>   // 1) check if pred(ElementType!Range.init, 
>> ElementType!Range.init) is equality
>>   // 2) check if isUnary!pred
>>   // 3) check if isBinary!pred
>> }
>
> For 2 and 3, there's std.traits.arity. However, as you point 
> out, it has some problems with templated functions. This 
> template will handle those cases in conjunction with 
> std.traits.arity:
>
> import std.traits : arity, isCallable;
>
> template arity(alias Fn, Args...)
> if (is(typeof(Fn!Args)) && isCallable!(typeof(Fn!Args)))
> {
>     enum arity = .arity!(Fn!Args);
> }
>
> unittest {
>     assert(arity!(() => 1) == 0);
>     assert(arity!(a => a, int) == 1);
>     assert(arity!((a,b) => a, int, float) == 2);
>
>     void test(T)(T,T,T) {}
>     assert(arity!(test, int) == 3);
> }

Thank you! That leading period too ... noice!

> Checking if a function is the equality function is much harder. 
> Consider this function:
>
> bool compare(int a, int b) {
>     if (a == 2 && b = 3) return true;
>     return a == b;
> }
>
> Clearly this is not an equality function, but for the vast 
> majority of inputs, it behaves exactly the same.
>
> There are other examples that make this hard. It's perfectly 
> possible to overload opEquals and have it ignore some fields, 
> or even access a database on the other side of the atlantic 
> ocean. In these cases, evaluating the equality of two objects 
> is not testable at compile time, and you simply cannot know.
>
> In your examples you use string functions ("a == b", e.g.). 
> These can of course be compared (you might want to do some 
> processing, as "a==b" should give the same result as "b        
> ==      a"). There's cases here where you can't be sure, of 
> course.
>
> All in all, I believe you're trying to solve the wrong problem, 
> but I might be wrong. Care to give a bit more information so I 
> get a better idea of why you want to do this?

Nah, your gut was spot on :D What I was trying to do didn't 
really make any sense. I'm learning D by playing with generic 
algorithms (trying to recreate a javascript functional library 
called lodash), and was trying to be "too smart". My thought 
process was I want a function that finds the intersection between 
two arrays, and I want to allow the user to pass in an equality 
predicate as well, in which case the intersection will return 
elements that return true for the equality predicate, and the 
algorithm would then not care about sortedness and do a naive 
O(n*m) approach (ie: for each element in a check if it exists in 
b and return it as one of the intersection elements).

If the predicate was not an equality predicate than it'd be 
assumed to be the predicate that was used to sort the array (in 
the case that they're sorted) and then a faster O(n) algorithm 
can be used.

The unary/binary stuff was to determine if the predicate was a 
unary predicate, in which case a transformation is applied to 
each elements and you have an algorithm that returns the 
transformed intersected elements.

Realized that the binary equality predicate is just a special 
case of the unary transformation predicate so I actually don't 
need to (and obviously as you point out can't reliable) test that 
a binary predicate is an equality one.

Cheers, and thanks for your input!




More information about the Digitalmars-d-learn mailing list