= Solution
The following <predicate> also checks the square's shape; `sort` is the three-way sorting <function> from Question 2:
``
valid :: [[Int]] -> Bool
valid rows =
let n = length rows
symbols = [1..n]
goodRows = all (\r -> sort r == symbols) rows
goodColumns = all (\j -> sort [r !! j | r <- rows] == symbols)
[0..n-1]
in goodRows && goodColumns
latin :: Int -> [[[Int]]]
latin = filter valid . squares
``
The row tests guarantee that each row has length $n$ and contains each allowed symbol once. Because `&&` tests this condition first, the later column indexing is safe for a finite total input. The column tests establish the remaining Latin-square condition. Filtering therefore retains precisely the valid squares; it does not remove any different ordering of rows, columns or symbols as an alleged symmetry duplicate.
Back to article page