function - 火卫一的纯度降低

标签 function d reduce purely-functional

为什么 Phobos 中的 std.algorithm.reduce 不是纯粹的?这是一个 Unresolved 问题还是有无法解决的原因?

这与以下问题有关吗: “纯函数是什么样的” Andrei 在 DConf 2013 的最后一次演讲中问道?

参见:http://forum.dlang.orgthread/[email protected]

我希望以下代码中的函数sparseness是纯粹的。我想我现在总是可以用 foreach 循环替换 reduce ,对吗?

import std.algorithm: reduce, min, max;
import std.typetuple: templateAnd;
import std.traits: isArray, Unqual;
import std.range: ElementType, isInputRange, isBidirectionalRange, isFloatingPoint;

//** Returns: true if $(D a) is set to the default value of its type. */
bool defaulted(T)(T x) @safe pure nothrow { return x == T.init; }
alias defaulted untouched;

/** Returns: Number of Default-Initialized (Zero) Elements in $(D range). */
size_t sparseness(T)(in T x, int recurseDepth = -1) @trusted /* pure nothrow */ {
    import std.traits: isStaticArray;
    static if (isStaticArray!T ||
               isInputRange!T) {
        import std.range: empty;
        immutable isEmpty = x.empty;
        if (isEmpty || recurseDepth == 0) {
            return isEmpty;
        } else {
            const nextDepth = (recurseDepth == -1 ?
                               recurseDepth :
                               recurseDepth - 1);
            static if (isStaticArray!T) { // TODO: We can't algorithms be applied to static arrays?
                typeof(return) ret;
                foreach (ref elt; x) { ret += elt.sparseness(nextDepth); }
                return ret;
            } else {
                import std.algorithm: map, reduce;
                return reduce!"a+b"(x.map!(a => a.sparseness(nextDepth)));
            }
        }
    } else static if (isFloatingPoint!T) {
        return x == 0; // explicit zero because T.init is nan here
    } else {
        return x.defaulted;
    }
}
unittest {
    assert(1.sparseness == 0);
    assert(0.sparseness == 1);
    assert(0.0.sparseness == 1);
    assert(0.1.sparseness == 0);
    assert(0.0f.sparseness == 1);
    assert(0.1f.sparseness == 0);
    assert("".sparseness == 1);
    assert(null.sparseness == 1);
    immutable ubyte[3]    x3   = [1, 2, 3];    assert(x3[].sparseness == 0);
    immutable float[3]    f3   = [1, 2, 3];    assert(f3[].sparseness == 0);
    immutable ubyte[2][2] x22  = [0, 1, 0, 1]; assert(x22[].sparseness == 2);
    immutable ubyte[2][2] x22z = [0, 0, 0, 0]; assert(x22z[].sparseness == 4);
}

更新:

我决定使用 isIterableforeach 而不是上面的,因为这对我现在来说也同样有效,并且使事情@safe pure nothro。我认为现在没有必要使用高阶函数来解决这个问题。我还发现 Davids Simchas 即将推出的 std.rational 在这里使用非常自然:

import rational: Rational;

/** Returns: Number of Default-Initialized (Zero) Elements in $(D x) at
    recursion depth $(D depth).
*/
Rational!ulong sparseness(T)(in T x, int depth = -1) @safe pure nothrow {
    alias R = typeof(return); // rational shorthand
    static if (isIterable!T) {
        import std.range: empty;
        immutable isEmpty = x.empty;
        if (isEmpty || depth == 0) {
            return R(isEmpty, 1);
        } else {
            immutable nextDepth = (depth == -1 ? depth : depth - 1);
            ulong nums, denoms;
            foreach (ref elt; x) {
                auto sub = elt.sparseness(nextDepth);
                nums += sub.numerator;
                denoms += sub.denominator;
            }
            return R(nums, denoms);
        }
    } else static if (isFloatingPoint!T) {
        return R(x == 0, 1); // explicit zero because T.init is nan here
    } else {
        return R(x.defaulted, 1);
    }
}

最佳答案

如果将 nextDepth 更改为 immutable 而不是 const,那么 sparseness 将是 pure.

我相信这是一个错误,它可能与传递给 reduce 捕获 nextDepth 的闭包有关,并且出于某种原因认为它可能是可变的,因为它是常量。然而,声明为 const 的值与声明为不可变的值相同——区别仅通过间接方式体现出来——所以我相信它是一个错误。

您可能希望将最小的重现案例作为错误提交。

(但是不能是 nothrow,因为 reduce 事实上可以抛出)

关于function - 火卫一的纯度降低,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20785670/

相关文章:

amazon-web-services - 在将AWS Lambda与Redis连接在一起时,任务在23.02秒错误后超时

c - 将数组值传递给另一个函数时出现缓冲区溢出问题

jquery - 使用 jQuery 从背景图像获取尺寸

case - 案例范围内开关案例的限制

arrays - D 编程语言字符数组

io - 二进制文件I/O

clojure - 为什么我的传感器功能比使用 ->> 运算符慢?

javascript - 在数组中查找具有下一个较低值的对象

c - 通过C函数返回指向数组的指针

python - 使类中的函数只能在不调用类的情况下访问