Мне подарили головоломку. Он состоит из 4 кубиков, расположенных рядом. Грани каждого куба одного из четырех цветов.
Чтобы решить головоломку, кубы должны быть ориентированы так, чтобы вершины всех четырех кубов были разными, все их фронты были разными, все их спины отличались, а все их днища были разными. Левая и правая стороны не имеют значения.
Мое решение с псевдокодом было:
- Создать представление каждого
куб.
- Получить все возможные ориентации
каждый куб (для каждого есть 24).
- Получить все возможные комбинации
ориентации каждого куба.
- Найти комбинацию ориентаций
что удовлетворяет решению.
Я решил головоломку, используя реализацию этого псевдокода в F #, но не удовлетворен тем, как я сделал шаг 3:
let problemSpace =
seq { for c1 in cube1Orientations do
for c2 in cube2Orientations do
for c3 in cube3Orientations do
for c4 in cube4Orientations do
yield [c1; c2; c3; c4] }
Приведенный выше код является очень конкретным и дает только декартово произведение четырех последовательностей ориентаций. Я начал думать о том, как написать его для n последовательностей ориентаций.
Я придумал (теперь весь код должен нормально работать в F # интерактиве):
// Used to just print the contents of a list.
let print =
Seq.fold (fun s i -> s + i.ToString()) "" >> printfn "%s"
// Computes the product of two sequences - kind of; the 2nd argument is weird.
let product (seq1:'a seq) (seq2:'a seq seq) =
seq { for item1 in seq1 do
for item2 in seq2 do
yield item1 |> Seq.singleton |> Seq.append item2 }
Функцию произведения можно использовать так ...
seq { yield Seq.empty }
|> product [ 'a'; 'b'; 'c' ]
|> product [ 'd'; 'e'; 'f' ]
|> product [ 'h'; 'i'; 'j' ]
|> Seq.iter print
... которые ведут к ...
let productn (s:seq<#seq<'a>>) =
s |> Seq.fold (fun r s -> r |> product s) (seq { yield Seq.empty })
[ [ 'a'; 'b'; 'c' ]
[ 'd'; 'e'; 'f' ]
[ 'h'; 'i'; 'j' ] ]
|> productn
|> Seq.iter print
Это именно то использование, которое я хочу. Productn имеет именно ту подпись, которую я хочу, и работает.
Тем не менее, использование продукта включает в себя неприятную строку seq {yield Seq.empty}, и оно неинтуитивно требует:
- Последовательность значений (seq <'a>)
- Последовательность последовательностей значений (seq >)
Второй аргумент кажется неверным.
Этот странный интерфейс хорошо спрятан productn, но все равно мучает меня.
Существуют ли более приятные и интуитивно понятные способы общего вычисления декартового произведения n последовательностей? Существуют ли какие-либо встроенные функции (или комбинации), которые делают это?