Search code examples
haskelltypessudokuquickcheck

How do you create quickCheck properties with a Property output in Haskell?


How do you create a property that checks that all solutions provided are valid solutions, I need it to output as a Property, but I'm unsure how to do that, I only understand how to do Bool outputs for quickCheck properties. See below for my attempt, and the general idea of how I want it to function:

solve :: Sudoku -> Maybe Sudoku
solve s = solve' (blanks s) s

solve' :: [Pos] -> Sudoku -> Maybe Sudoku
solve' blankl s
    | not (isOkay s)        = Nothing
    | isFilled s            = Just s
    | otherwise             = listToMaybe [fromJust sol | n <- [1..9], 
                                            let sol = solve' (tail blankl) (update s (head blankl) (Just n)),
                                            sol /= Nothing]

isSolutionOf :: Sudoku -> Sudoku -> Bool
isSolutionOf s1 s2 = 
    isOkay s1 
    && isFilled s1
    && and [ a == b || b == Nothing | 
             (a,b) <- zip (concat (rows s1)) (concat (rows s2)) ]

prop_SolveSound :: Sudoku -> Property
prop_SolveSound s 
    | solution == Nothing = True
    | otherwise           = isSolutionOf (fromJust solution) s where
                              solution = solve s

Any help is much appreciated, I guess what I'm asking is how can you convert the - quite clearly - Bool output from prop_SolveSound to a Property output?


Solution

  • At the very simplest, you can use property method to convert e.g. Bool to Property. I suggest to look at the instances of Testable class, and try to understand what each of them does, and how it can be used.

    Or you can be more sophisticated and use some other functions returning Property, e.g. ===. That might be tricky in your example.

    One quite useful function, is counterexample. It allows you to print additional output, when property doesn't hold. For example, it's used to implement ===:

    (===) :: (Eq a, Show a) => a -> a -> Property
    x === y =
      counterexample (show x ++ interpret res ++ show y) res
      where
        res = x == y
        interpret True  = " == "
        interpret False = " /= "
    

    As this is an assignment, I'm not giving you any more hints.