Can traits in D be used for type classes?

爱⌒轻易说出口 提交于 2019-12-03 05:52:15
template genericfunctions() {
  T TestMonoid(T,N = Monoid!T)(T a) {
    return N.mappend(N.mzero(),a);
  }
}

No need for that:

T TestMonoid(T,N = Monoid!T)(T a) {
  return N.mappend(N.mzero(),a);
}

That should suffice. With this, there's no need for the mixin either.

Is it possible to define constraints like the functor laws with unittest in D?

Not entirely sure I understand what you are asking for, but you can define contraints with template functions/classes:

void isEven(T)(T x) if (isIntegral!T) { return x % 2 == 0; }

This template will only then instantiate if T is an integral type.

See the 'Template Constraints' section at the bottom of the Templates page.

Rather than answer your question, as that would require understanding what you have said. I'm just going to ramble on about features of D that you are using and those that might be of use to you.

D doesn't have Type Classes (as you know). Instead it has type specialization (which you are using) and template constraints. Type specialization came prior to template constraints and can in fact be used there.

A template constraint allows you to require certain properties of a type. You will find this is heavily used in std.range and there are templates which help write such constraints in std.traits. I may do a more complicated example but for now, this accepts types which convert to int:

void myFunction(T)(T param) if(is(T:int)) {
}

Is it possible to define constraints like the functor laws with unittest in D? That would be very nice.

Phobos has another concept on top of the language, as monoids and functors and monads would be. And that is Ranges. Now the way Phobos is checking if a type is a range is by defining a template that checks if certain functions can be called on a type. If these functions are generic themselves, the answer of the template would depend on the compiler being able to find a method matching your type.

For refenrence, here's the typecheck for a ForwardRange (Link points to code with more docs):

template isInputRange(R)
{
    enum bool isInputRange = is(typeof(
    (inout int = 0)
    {
        R r = R.init;     // can define a range object
        if (r.empty) {}   // can test for empty
        r.popFront();     // can invoke popFront()
        auto h = r.front; // can get the front of the range
    }));
}

With that you can create a template constraint like so:

template isFunctor(Testant) {
    enum bool isFunctor = is(typeof(
        ()
        {
            Testant t = Testant.init;          // can instantiate that type
            auto result = t.fmap((Testant){}); // can call fmap on it with the type as parameter.
        }
}

Note the UFCS with fmap above, fmap still matches your decalaration.

Also note that it might be better to use structs instead of classes. Since they are value types and we can have Compile Time Function Execution (CTFE) in D, with clever usage of opCall you can use them as if they were functions themselves.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!