Function 火卫一纯度降低

Function 火卫一纯度降低,function,d,reduce,purely-functional,Function,D,Reduce,Purely Functional,为什么火卫一中的std.algorithm.reduce不是纯的?这是一个未解决的问题还是有原因不能解决 这个问题有什么需要解决的吗 “纯函数是什么样子的” 安德烈在2013年DConf的最后一次演讲中问道 见: 我希望下面代码中的函数稀疏性是纯的。我想我现在总可以用一个foreach循环来代替reduce,对吗 import std.algorithm: reduce, min, max; import std.typetuple: templateAnd; import std.traits

为什么火卫一中的
std.algorithm.reduce
不是纯的?这是一个未解决的问题还是有原因不能解决

这个问题有什么需要解决的吗 “纯函数是什么样子的” 安德烈在2013年DConf的最后一次演讲中问道

见:

我希望下面代码中的函数
稀疏性
是纯的。我想我现在总可以用一个
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);
}
更新:

我决定改用
isinterable
foreach
来代替上面的内容,因为这对我现在来说同样有效,并且使
@完全安全。我认为现在没有必要使用高阶函数来解决这个问题。我还发现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
,则
稀疏性将是

我认为这是一个bug,可能与传递给
reduce
捕获
nextDepth
的闭包有关,出于某种原因,我认为它可能是可变的,因为它是
const
。然而,声明为
const
的值与声明为
immutable
的值是相同的——区别只表现为间接的——因此我认为这是一个错误

您可能希望将一个最小的复制案例作为bug归档


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

如果您将
nextDepth
更改为
不可变的
而不是
const
,那么
稀疏性将是
纯粹的

我认为这是一个bug,可能与传递给
reduce
捕获
nextDepth
的闭包有关,出于某种原因,我认为它可能是可变的,因为它是
const
。然而,声明为
const
的值与声明为
immutable
的值是相同的——区别只表现为间接的——因此我认为这是一个错误

您可能希望将一个最小的复制案例作为bug归档


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

这可能是由于unaryFunc帮助程序不是纯的。如果将“a+b”改为引用一个显式标记为纯的单独函数,会发生什么情况?因此,就像模块范围内的纯整数add(inta,intb){returna+b;}
一样,然后
reduce!添加(…)
。我知道这有点麻烦,但我只是想看看会发生什么。(我会检查自己,但我的电缆仍在家中,因此无法远程连接,而且我的设备上没有开发工具!)这可能是由于unaryFunc助手不纯粹。如果将“a+b”改为引用一个显式标记为纯的单独函数,会发生什么情况?因此,就像模块范围内的纯整数add(inta,intb){returna+b;}
一样,然后
reduce!添加(…)
。我知道这有点麻烦,但我只是想看看会发生什么。(我会检查自己,但我的电缆仍在家中,因此无法远程连接,而且我的设备上没有开发工具!)