"Given a nonempty stream of [[Summable]] values, return the 
 sum of the values.
 
     {Float+} values = ... ;
     Float total = sum(values);
 
 For the case of a possibly-empty stream, form a nonempty 
 stream starting with the zero element (the [[additive 
 identity|Summable]]).
 
     {Float*} values = ... ;
     Float total = sum { 0.0, *values };
 
 For the case of a stream of `Integer`s, `Float`s, or
 `String`s, prefer [[Integer.sum]], [[Float.sum]], or
 [[String.sum]]."
see (`function product`, 
     `function Integer.sum`,
     `function Float.sum`,
     `function String.sum`)
tagged("Streams", "Numbers")
shared native Value sum<Value>({Value+} values) 
        given Value satisfies Summable<Value>;

shared native("js") Value sum<Value>({Value+} values) 
        given Value satisfies Summable<Value> {
    value it = values.iterator();
    assert (!is Finished first = it.next());
    variable value sum = first;
    while (!is Finished val = it.next()) {
        sum += val;
    }
    return sum;
}

shared native("jvm") Value sum<Value>({Value+} values) 
        given Value satisfies Summable<Value> {
    value it = values.iterator();
    switch (first = it.next())
    case (is Integer) {
        // unbox; don't infer type Value&Integer
        variable Integer sum = first;
        while (is Integer val = it.next()) {
            Integer unboxed = val;
            sum += unboxed;
        }
        assert (is Value result = sum);
        return result;
    }
    case (is Float) {
        // unbox; don't infer type Value&Float
        variable Float sum = first;
        while (is Float val = it.next()) {
            Float unboxed = val;
            sum += unboxed;
        }
        assert (is Value result = sum);
        return result;
    }
    case (is String) {
        value sum = StringBuilder();
        sum.append(first);
        while (is String val = it.next()) {
            sum.append(val);
        }
        assert (is Value result = sum.string);
        return result;
    }
    case (is Finished) {
        assert (false);
    }
    else {
        variable value sum = first;
        while (!is Finished val = it.next()) {
            sum += val;
        }
        return sum;
    }
}