D中的特征可以用于类型类吗? [英] Can traits in D be used for type classes?

查看:90
本文介绍了D中的特征可以用于类型类吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是D的新手,我正在寻找一种使用Haskell类型类编程的好方法,例如Functors,Monoid等等。

类似于在Tango或Phobos中实现的功能吗?

我听说过某些特性可以编译时检查类型的特征。它们可以用于类型类吗?



我已经尝试了一些模板特化,并提出了这个问题:

  // Monoid.d 
//通用Monoid在没有类型为Monoid的实例时被调用T
class Monoid(T){
pragma(msg,类型不是Monoid);
}

//双重
的Monoid实例Monoid(T:double){
static T mzero(){return 0; }
static b mappend(T a,T b){return a + b;}
}

// int的单变量实例$ b $ 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; 
导入std.stdio;
导入std.conv;
mixin genericfunctions;

void main(){
writefln(to!string(TestMonoid(3)));
writefln(to!string(TestMonoid(3.3243)));
}

您现在可以使用int和double作为Monoid。



然而当你有一个像Functor这样的实例本身就是泛型类型的类时,事情会变得更加复杂:

 模块函子; 

//通用函数,如通用Monoid
类Functor(别名T,A){
pragma(msg,不是Functor的一个实例);
}

//非常简单的容器来演示函数行为
class FunctorTest(A){
public A a;
this(A a){
this.a = a;



// FunctorTest的实例!
类Functor(别名T:FunctorTest,A){
static T!B fmap(B)(T!A a,B delegate(A)fn){
return new T!B(fn(aa));


一种算法看起来像这样:

  template genericfunctions(){
T TestMonoid(T,N = Monoid!T)(T a){
return N.mappend(N.mzero()的一个);
}

// F是Functor,之前的函数类型,
// B函子类型之后,N是函数的实例
F! B fmap(别名F,A,B,N = Functor!(F,A))(F!A a,B委托(A)fn){
返回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));
}

但是,如果您想为Type使用另一个Functor实例,则必须指定fmap的所有4个类型参数。有没有一种方法,你只需要指定实例,其他参数可以从这里推导出来?



是否有另外一种笨拙的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 );
}

这就够了。因此,不需要 mixin


是否有可能定义约束条件
,像函数法则,单元测试在
D?


不完全确定我明白你是什么(T)(T x)如果(isIntegral()),则可以使用模板函数/类来定义约束:

  !T){return x%2 == 0; } 

这个模板只会在 T 是一个整数类型。



请参阅 Templates 页面。


I'm new to D, and I'm looking for a good way to program with Haskell-like type classes e.g. Functors, Monoids, etc. in D.

Is something like this implemented in Tango or Phobos?

I've heard about traits which enable compile-time type checking for certain properties. Can they be used for type classes?

I've tried a little bit with template specialization and come up with this:

// 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;}
}

A generic algorithm whose type parameter needs to be a Monoid could then be expressed as:

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

However, if you want to omit the template parameters, you have to import all needed Monoid instances and mixin the genericfunctions template.

import Monoid;
import std.stdio;
import std.conv;
mixin genericfunctions;

void main() {
    writefln(to!string(TestMonoid(3))); 
    writefln(to!string(TestMonoid(3.3243))); 
}

You can now use ints and doubles as Monoids.

However things get more complex when you have a type class like Functor whose instances are itself generic:

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));
    }
}

One algorithm would look like this:

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);
    }
}

Luckily, you can omit the four template parameters when you use it:

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));
}

But when you want to use another Functor instance for the Type you have to specify all 4 type parameters of fmap. Is there a way in which you only need to specify the Instance and the other parameters could be deduced from this?

Is there an alternative to the clumsy mixin workaround?

Are there other disadvantages of this approach which I don't see?

What about other ways?

Thanks for reading this far and for taking the time to think and answer :)


Edit:

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

解决方案

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.

这篇关于D中的特征可以用于类型类吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆