"Given a stream of [[Comparable]] values, return the 
 smallest value in the stream, or `null` if the stream is
 empty.
 
 For any nonempty stream `it`, `min(it)` evaluates to the 
 first element of `it` such that for every element `e` of 
 `it`, `min(it) <= e`.
 
 Any value `x` which violates the reflexivity requirement of
 [[Object.equals]] such that `x!=x` is skipped, unless it is
 the last element in the stream. Thus, for a stream of 
 [[Float]]s, `min()` will not return an
 [[undefined value|Float.undefined]] unless every element of
 the stream is undefined."
see (`interface Comparable`, 
     `function max`,
     `function smallest`)
tagged("Comparisons", "Streams")
shared native Absent|Value min<Value,Absent>
        (Iterable<Value,Absent> values) 
        given Value satisfies Comparable<Value>
        given Absent satisfies Null;

shared native("js") Absent|Value min<Value,Absent>
        (Iterable<Value,Absent> values) 
        given Value satisfies Comparable<Value>
        given Absent satisfies Null {
    value it = values.iterator();
    if (!is Finished first = it.next()) {
        variable value min = first;
        while (min!=min, //quick test for NaN
              !is Finished val = it.next()) {
            min = val;
        }
        while (!is Finished val = it.next()) {
            if (val<min) {
                min = val;
            }
        }
        return min;
    }
    else {
        "iterable must be empty"
        assert (is Absent null);
        return null;
    }
}

shared native("jvm") Absent|Value min<Value,Absent>
        (Iterable<Value,Absent> values)
        given Value satisfies Comparable<Value>
        given Absent satisfies Null {
    
    value it = values.iterator();
    switch (first = it.next())
    case (is Finished) {
        "iterable must be empty"
        assert (is Absent null);
        return null;
    }
    case (is Integer) {
        variable Integer min = first;
        while (is Integer val = it.next()) {
            if ((val of Integer) < min) {
                min = val;
            }
        }
        assert (is Value result = min);
        return result;
    }
    case (is Float) {
        variable Float min = first;
        while (min!=min,
               is Float val = it.next()) {
            min = val;
        }
        while (is Float val = it.next()) {
            if ((val of Float) < min) {
                min = val;
            }
        }
        assert (is Value result = min);
        return result;
    }
    else {
        variable value min = first;
        //exactly reproduce behavior on JS above
        while (min!=min,
              !is Finished val = it.next()) {
            min = val;
        }
        while (!is Finished val = it.next()) {
            if (val<min) {
                min = val;
            }
        }
        return min;
    }
}