Minimum of empty Seq is infinite, Why?

Viewed 465

I'm working on this weeks PerlWChallenge.

You are given an array of integers @A. Write a script to create an array that represents the smaller element to the left of each corresponding index. If none found then use 0.

Here's my approach:

my @A = (7, 8, 3, 12, 10);
my $L = @A.elems - 1;

say gather for 1 .. $L -> $i { take @A[ 0..$i-1 ].grep( * < @A[$i] ).min };

Which kinda works and outputs:

(7 Inf 3 3)

The Infinity obviously comes from the empty grep. Checking:

> raku -e "().min.say"
Inf

But why is the minimum of an empty Seq Infinity? If anything it should be -Infinity. Or zero?

It's probably a good idea to test for the empty sequence anyway.

I ended up using

take .min with @A[ 0..$i-1 ].grep( * < @A[$i] ) or 0

or

take ( @A[ 0..$i-1 ].grep( * < @A[$i] ) or 0 ).min
4 Answers

Generally, Inf works out quite well in the face of further operations. For example, consider a case where we have a list of lists, and we want to find the minimum across all of them. We can do this:

my @a = [3,1,3], [], [-5,10];
say @a>>.min.min

And it will just work, since (1, Inf, -5).min comes out as -5. Were min to instead have -Inf as its value, then it'd get this wrong. It will also behave reasonably in comparisons, e.g. if @a.min > @b.min { }; by contrast, an undefined value will warn.

TL;DR say min displays Inf.


min is, or at least behaves like, a reduction.


Per the doc for reduction of a List:

When the list contains no elements, an exception is thrown, unless &with is an operator with a known identity value (e.g., the identity value of infix:<+> is 0).


Per the doc for min:

a comparison Callable can be specified with the named argument :by

by is min's spelling of with.


To easily see the "identity value" of an operator/function, call it without any arguments:

say min # Inf

Imo the underlying issue here is one of many unsolved wide challenges of documenting Raku. Perhaps comments here in this SO about doc would best focus on the narrow topic of solving the problem just for min (and maybe max and minmax).

I think, there is inspiration from infimum (the greatest lower bound). Let we have the set of integers (or real numbers) and add there the greatest element Inf and the lowest -Inf. Then infimum of the empty set (as the subset of the previous set) is the greatest element Inf. (Every element satisfies that is smaller than any element of the empty set and Inf is the greatest element that satisfies this.) Minimum and infimum of any nonempty finite set of real numbers are equal.

Similarly, min in Raku works as infimum for some Range.

1 ^.. 10
andthen .min;   #1

but 1 is not from 1 ^.. 10, so 1 is not minimum, but it is infimum of the range.

It is useful for some algorithm, see the answer by Jonathan Worthington or

q{3 1 3
  -2
  --
  -5 10
}.lines
andthen .map: *.comb( /'-'?\d+/ )».Int # (3, 1, 3), (-2,), (), (-5, 10)
andthen .map: *.min                    # 1,-2,Inf,-5
andthen .produce: &[min]
andthen .fmt: '%2d',','                # 1,-2,-2,-5

this (from the docs) makes sense to me

method min(Range:D:)
Returns the start point of the range.

say (1..5).min;                                   # OUTPUT: «1␤» 
say (1^..^5).min;                                 # OUTPUT: «1␤»

and I think the infinimum idea is quite a good mnemonic for the excludes case which also could be 5.1^.. , 5.0001^.. etc.

Related