【发布时间】:2011-06-13 09:02:42
【问题描述】:
我是 D 新手,我正在寻找一种使用类似 Haskell 的类型类进行编程的好方法,例如D 中的 Functors、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)));
}
您现在可以将整数和双精度数用作 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));
}
但是当你想为 Type 使用另一个 Functor 实例时,你必须指定 fmap 的所有 4 个类型参数。有没有办法只需要指定Instance,其他参数就可以推导出来了?
是否有替代笨拙的 mixin 解决方法的方法?
这种方法还有其他我看不到的缺点吗?
其他方式呢?
感谢您阅读本文并花时间思考和回答:)
编辑:
是否可以在 D 中使用 unittest 定义函子定律等约束?那就太好了。
【问题讨论】:
-
不那么笨拙的方法可能是放弃在非 FP 语言中模仿纯 FP 的构造。根据您尝试做的事情,它可能(或可能不会)更容易。
-
D 是一种多范式语言,对 FP 有很好的支持,例如目前我知道的仅在 Haskell 中才有的一流函数和 PURE 函数。类型类是一个非常强大的功能,因为它们可以进行抽象编程。它们相对于继承的优势在于您可以将属性添加到现有类型。如果您有一个接口 Monoid,您将无法将 int 用作 monoid 或之前构造的其他类型。而且我认为可以将它们放在 D 中。这里很难在函数端实现,但在调用方你不认识它。
标签: functional-programming d typeclass