Task

Show one or more idiomatic ways of generating the Cartesian product of two arbitrary lists in your language.

Demonstrate that your function/method correctly returns:

{1, 2} × {3, 4} = {(1, 3), (1, 4), (2, 3), (2, 4)}
and, in contrast:

{3, 4} × {1, 2} = {(3, 1), (3, 2), (4, 1), (4, 2)}
Also demonstrate, using your function/method, that the product of an empty list with any other list is empty.

 {1, 2} × {} = {}
 {} × {1, 2} = {}
For extra credit, show or write a function returning the n-ary product of an arbitrary number of lists, each of arbitrary length. Your function might, for example, accept a single argument which is itself a list of lists, and return the n-ary product of those lists.

Use your n-ary Cartesian product function to show the following products:

 {1776, 1789} × {7, 12} × {4, 14, 23} × {0, 1}
 {1, 2, 3} × {30} × {500, 100}
 {1, 2, 3} × {} × {500, 100}


sub cartesian {
    my $sets = shift @_;
    for (@$sets) { return [] unless @$_ }
 
    my $products = [[]];
    for my $set (reverse @$sets) {
        my $partial = $products;
        $products = [];
        for my $item (@$set) {
            for my $product (@$partial) {
                push @$products, [$item, @$product];
            }
        }
    }
    $products;
}
 
sub product {
    my($s,$fmt) = @_;
    my $tuples;
    for $a ( @{ cartesian( \@$s ) } ) { $tuples .= sprintf "($fmt) ", @$a; }
    $tuples . "\n";
}
 
print 
product([[1, 2],      [3, 4]                  ], '%1d %1d'        ).
product([[3, 4],      [1, 2]                  ], '%1d %1d'        ).
product([[1, 2],      []                      ], '%1d %1d'        ).
product([[],          [1, 2]                  ], '%1d %1d'        ).
product([[1,2,3],     [30],   [500,100]       ], '%1d %1d %3d'    ).
product([[1,2,3],     [],     [500,100]       ], '%1d %1d %3d'    ).
product([[1776,1789], [7,12], [4,14,23], [0,1]], '%4d %2d %2d %1d')