Alright so I am attempting to create a Sudoku Solver in Haskell but I’m getting an error saying that I couldn’t match the expected type [[Int]] with the actual type IO (). Here is my attempt at the recursive solver, the error message, and other relevant pieces of code:
Recursive Solver Attempt:
test i j q s_board = if ((valid_row i q s_board )&&(valid_column j q s_board)&& (valid_sub_board i j q s_board)) then (solve (set_value i j q s_board)) else s_board
foo i j s_board = if ((get_value i j s_board) == 0) then [test i j q s_board | q <- [1..9]] else s_board
solve s_board = if (full_board s_board) then (print_board s_board) else [foo i j s_board | i <- [0..8], j <- [0..8]]
This question would be extremely long if I included all the definitions for the valid column, row, etc. functions, but I’ve checked to make sure those work. With this code I’m getting the following error message:
Couldn't match expected type `[[Int]]' with actual type `IO ()'
In the return type of a call of `print_board'
In the expression: (print_board s_board)
In the expression:
if (full_board s_board) then
(print_board s_board)
else
[foo i j s_board | i <- [0 .. 8], j <- [0 .. 8]]
Also here is the code that I’m using to print my board:
-- showLine: this function provides formating for a single row
showLine :: [Int] -> String
showLine = intercalate " | "
. map unwords
. chunksOf 3
. map show
-- showBoad: this function provides formating for the entire board
showBoard :: [[Int]] -> String
showBoard = intercalate "---------------------\n"
. map unlines
. chunksOf 3
. map showLine
-- print_board: this function is meant to print out the entire board
print_board :: [[Int]] -> IO ()
print_board s_board = putStrLn $ showBoard s_board
Do you guys see what’s the problem with what I have so far. I’m totally new to Haskell and this is the first real program that I’ve attempted. Any help would be greatly appreciated.
The two branches of an
ifmust have the same types, but inthe
Truebranch has type IO (), while theFalsebranch is a list of things (boards, in this case probably), so the type is[a], iffoo :: Int -> Int -> [[Int]] -> a.You should separate concerns, the recursive backtracking should give you a list of (full) boards, the printing should be done from another context that calls
solve.My suggestion would be something along the lines of
so each of these functions returns a list of
Grids, and a dead-end is pruned by returning an empty list of solutions that can be reached from the current grid. When there is no dead-end yet diagnosed, all allowed combinations are tried.You could then have
But, that would produce the same solutions multiple times, and be terribly inefficient for an exhaustive search, since evry combination of guesses would be made in all possible orders.
So, let’s take a look at how we could make it more efficient. We can prune the permutations and repetitions of solutions in the result list, if we have an algorithm to choose the next position at which we guess a value. The simplest such algorithm is to pick the first free cell. So let s write a function to find the free cells of a grid.
With that, we also have a test whether the grid is full,
full_board = null . free_cells, by the way. So we can start our solvingNext, we find the values we might place in the cell
(i,j),and place them in the cell and proceed further