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!


Reply via email to