That representation of a Sudoku is elegant, but I think it is not the most natural representation. The base constraint programming style will use a variable per square with domain 1-9, and then 27 all_different constraints. This representation is a lot closer to how people talk about the rules of Sudoku, which in my mind makes it more natural.
A full MiniZinc program would look like this
int: n = 3;
int: s = n*n;
set of int: S = 1..s;
array[S, S] of opt S: puzzle;
array[S, S] of var S: board;
% Sudoku constraints
constraint forall(row in S) ( all_different(board[row, ..]) );
constraint forall(col in S) ( all_different(board[.., col]) );
constraint forall(r, c in {1, 4, 7}) (
all_different(board[r..<r+n, c..<c+n])
);
% Set up puzzle
constraint forall (r, c in S where occurs(puzzle[r, c])) (
board[r, c] = puzzle[r, c]
);
solve satisfy;
And an instance file looks like this puzzle = [|
9, <>, 8, 1, <>, <>, <>, <>, 4 |
1, 2, <>, <>, 8, 6, <>, 5, <> |
<>, <>, 7, <>, <>, <>, <>, 1, <> |
<>, 8, 3, <>, <>, <>, <>, 6, 9 |
7, <>, 6, 8, <>, 3, <>, <>, <> |
<>, <>, <>, 4, 6, <>, <>, 8, <> |
<>, <>, <>, <>, <>, 1, <>, <>, <> |
<>, <>, <>, <>, <>, 4, 5, <>, 1 |
5, 4, 1, 9, 3, 8, <>, <>, <>
|];