Note that there are some explanatory texts on larger screens.

plurals
  1. POCan traits in D be used for type classes?
    text
    copied!<p>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.</p> <p>Is something like this implemented in Tango or Phobos? </p> <p>I've heard about traits which enable compile-time type checking for certain properties. Can they be used for type classes?</p> <p>I've tried a little bit with template specialization and come up with this:</p> <pre><code>// 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;} } </code></pre> <p>A generic algorithm whose type parameter needs to be a Monoid could then be expressed as:</p> <pre><code>template genericfunctions() { T TestMonoid(T,N = Monoid!T)(T a) { return N.mappend(N.mzero(),a); } } </code></pre> <p>However, if you want to omit the template parameters, you have to import all needed Monoid instances and mixin the <code>genericfunctions</code> template.</p> <pre><code>import Monoid; import std.stdio; import std.conv; mixin genericfunctions; void main() { writefln(to!string(TestMonoid(3))); writefln(to!string(TestMonoid(3.3243))); } </code></pre> <p>You can now use ints and doubles as Monoids.</p> <p>However things get more complex when you have a type class like Functor whose instances are itself generic:</p> <pre><code>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)); } } </code></pre> <p>One algorithm would look like this:</p> <pre><code>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); } } </code></pre> <p>Luckily, you can omit the four template parameters when you use it:</p> <pre><code>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)); } </code></pre> <p>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?</p> <p>Is there an alternative to the clumsy mixin workaround?</p> <p>Are there other disadvantages of this approach which I don't see? </p> <p>What about other ways?</p> <p>Thanks for reading this far and for taking the time to think and answer :)</p> <hr> <p><strong>Edit:</strong></p> <p>Is it possible to define constraints like the functor laws with unittest in D? That would be very nice.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload