是否可以在D?
中统一实施amb运算符 http://www.haskell.org/haskellwiki/Amb
http://www.randomhacks.net/articles/2005/10/11/amb-operator
排序我想到的是:
amb([1, 2]) * amb([3, 4, 5]) == amb([3, 4, 5, 6, 8, 10])
amb(["hello", "world"]) ~ amb(["qwerty"]) == amb(["helloqwerty", "worldqwerty"])
amb(["hello", "world"]) ~ "qwerty" == amb(["helloqwerty", "worldqwerty"])
amb(["hello", "very long string"]).length = amb([5, 16])
在最后两个例子中,确实需要将〜和.length“提升”到amb'上下文'(monad?)。在前两个示例中,运算符应该只应用于amb的内容。
我已经给了它一个简短的尝试,但是在尝试解除包装类型的运算符/方法/属性(在此示例中为*,〜和.length)时遇到了问题。应如何在D?
中完成谢谢,
克里斯。
答案 0 :(得分:12)
是的,有可能。这就是我想出来的。
import std.range;
import std.algorithm;
import std.stdio;
import std.functional;
import std.math;
import std.string;
struct AmbRange(R1, R2, alias Op)
{
public:
this(R1 _r1, R2 _r2) { r1 = _r1; r2 = r2c = _r2; }
void popFront()
{
r2.popFront();
if (r2.empty) { r2 = r2c; r1.popFront(); }
}
@property auto front() { return Op(r1.front, r2.front); }
@property bool empty() { return r1.empty; }
private:
R1 r1;
R2 r2, r2c;
}
struct Amb(R)
{
alias ElementType!(R) E;
public:
this(R r) { this.r = r; }
auto opBinary(string op, T)(T rhs) if (!is(T U : Amb!(U)))
{
alias binaryFun!("a"~op~"b") Op;
return map!((E e) { return Op(e, rhs); })(r);
}
auto opBinaryRight(string op, T)(T lhs) if (!is(T U : Amb!(U)))
{
alias binaryFun!("a"~op~"b") Op;
return map!((E e) { return Op(lhs, e); })(r);
}
auto opBinary(string op, T)(T rhs) if (is(T U : Amb!(U)))
{
alias binaryFun!("a"~op~"b") Op;
return AmbRange!(R, typeof(rhs.r), Op)(r, rhs.r);
}
auto opDispatch(string f, T ...)(T args)
{
mixin("return map!((E e) { return e."~f~"(args); })(r);");
}
auto opDispatch(string f)()
{
mixin("return map!((E e) { return e."~f~"; })(r);");
}
private:
R r;
}
auto amb(R)(R r) { return Amb!R(r); }
void main()
{
auto r1 = 2 * amb([1, 2, 3]);
assert(equal(r1, [2, 4, 6]));
auto r2 = amb(["ca", "ra"]) ~ "t";
assert(equal(r2, ["cat", "rat"]));
auto r3 = amb(["hello", "cat"]).length;
assert(equal(r3, [5, 3]));
auto r4 = amb(["cat", "pat"]).replace("a", "u");
assert(equal(r4, ["cut", "put"]));
auto r5 = amb([1, 2]) * amb([1, 2, 3]);
assert(equal(r5, [1, 2, 3, 2, 4, 6]));
}
非常感谢BCS解决如何解决binaryOp模糊问题。
我必须创建一个新的范围来遍历两个Amb
之间的二元运算结果,但我认为无论如何都是最好的。
对于那些刚接触D并且很好奇的人来说,所有string
的东西都是在编译时完成的,所以在运行时没有解析代码或类似的东西 - 它几乎和手工一样有效 - 用C编码。