D中的特征可以用于类型类吗?

| 我是D的新手,我正在寻找一种使用类似Haskell的类型类进行编程的好方法,例如D中的函子,Monoids等。 在Tango或Phobos中是否实现了类似的功能? 我听说过一些特性,这些特性可以对某些属性进行编译时类型检查。它们可以用于类型类吗? 我已经尝试了一些模板专业化,并提出了以下建议:
// Monoid.d
// generic Monoid gets called when there is no instance of Monoid for Type T
class Monoid(T) {
    pragma(msg, \"Type is not a Monoid\");
}

// Monoid instance for double
class Monoid(T:double) {
    static T mzero() { return 0; }
    static T mappend(T a, T b ) { return a + b;}
}

// Monoid instance for int
class Monoid(T:int) {
    static T mzero() { return 0; }
    static T mappend(T a, T b ) { return a + b;}
}
然后将类型参数需要为Monoid的通用算法表示为:
template genericfunctions() {
    T TestMonoid(T,N = Monoid!T)(T a) {
        return N.mappend(N.mzero(),a);
    }
}
但是,如果要忽略模板参数,则必须导入所有需要的Monoid实例并混入
genericfunctions
模板。
import Monoid;
import std.stdio;
import std.conv;
mixin genericfunctions;

void main() {
    writefln(to!string(TestMonoid(3))); 
    writefln(to!string(TestMonoid(3.3243))); 
}
现在,您可以将int和double用作Monoid。 但是,当您拥有类似实例的Functor类型类时,事情就变得更加复杂了:
module Functors;

// generic Functor like generic Monoid
class Functor(alias T, A) {
    pragma(msg,\"Not an instance of Functor\");
}

// very simple container to demonstrate functors behavior
class FunctorTest(A) {
    public A a; 
    this(A a) {
        this.a = a; 
    }
}

// instance of Functor for FunctorTest!A 
class Functor(alias T:FunctorTest,A) {
    static T!B fmap(B)(T!A a, B delegate(A) fn) {
        return new T!B(fn(a.a));
    }
}
一种算法如下所示:
template genericfunctions() {
    T TestMonoid(T,N = Monoid!T)(T a) {
        return N.mappend(N.mzero(),a);
    }

    // F is the Functor, A the functors type before,
    // B the functors Type after, N is the instance of Functor
    F!B fmap(alias F,A,B,N=Functor!(F,A))(F!A a, B delegate(A) fn) {
        return N.fmap!B(a,fn);
    }
}
幸运的是,使用时可以省略四个模板参数:
mixin genericfunctions;

void main() {
    auto a = new FunctorTest!int(3);
    auto b = fmap(a,(int b) {return b+ 0.5;});
    writefln(to!string(b.a));
}
但是,当您要将另一个Functor实例用于Type时,必须指定fmap的所有4个type参数。有没有一种方法您只需要指定实例,就可以从中推导出其他参数? 有什么替代笨拙的mixin解决方法的方法吗? 我没有看到这种方法的其他缺点吗? 那其他方式呢? 感谢您阅读本文并抽出时间思考和回答:) 编辑: 是否可以使用D中的unittest来定义像函子定律这样的约束?那肯定很不错。     
已邀请:
        
template genericfunctions() {
  T TestMonoid(T,N = Monoid!T)(T a) {
    return N.mappend(N.mzero(),a);
  }
}
不需要:
T TestMonoid(T,N = Monoid!T)(T a) {
  return N.mappend(N.mzero(),a);
}
这样就足够了。这样,也不需要9英镑。   是否可以定义约束   就像在单元测试中的函子定律   D吗 不能完全确定我了解您的要求,但是您可以使用模板函数/类来定义约束:
void isEven(T)(T x) if (isIntegral!T) { return x % 2 == 0; }
仅当
T
是整数类型时,此模板才会实例化。 请参阅“模板”页面底部的“模板约束”部分。     
        与其回答您的问题,不如回答您的问题。我只是在讨论您正在使用的D的功能以及可能对您有用的那些功能。 D没有类型类(如您所知)。相反,它具有类型专用化(您正在使用)和模板约​​束。类型专门化先于模板约束,实际上可以在模板约束中使用。 模板约束允许您要求类型的某些属性。您会发现它在std.range中大量使用,并且有一些模板可以帮助在std.traits中编写此类约束。我可能会做一个更复杂的示例,但是现在,它接受转换为int的类型:
void myFunction(T)(T param) if(is(T:int)) {
}
    
           是否可以使用D中的unittest来定义像函子定律这样的约束?那肯定很不错。 Phobos在语言之上还有另一个概念,就像Monoid,函子和Monad一样。那就是范围。现在,Phobos检查类型是否为范围的方法是定义一个模板,该模板检查是否可以在类型上调用某些函数。如果这些函数本身是通用的,模板的答案将取决于编译器是否能够找到与您的类型匹配的方法。 为了防卫,这是ForwardRange的类型检查(链接指向带有更多文档的代码):
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
    }));
}
这样,您可以创建一个模板约束,如下所示:
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.
        }
}
注意上面带有fmap的UFCS,fmap仍然与您的声明匹配。 另请注意,最好使用结构而不是类。由于它们是值类型,并且我们可以在D中包含编译时函数执行(CTFE),因此可以巧妙地使用opCall来使用它们,就好像它们是函数本身一样。     

要回复问题请先登录注册