I'm trying to solve the 8 queens problem in Haskell without the use of any advanced functions, only with basic knowledge. I have come this far only but I'm getting an error that I can't understand. The code:
queens = [[x1,x2,x3,x4,x5,x6,x7,x8] | x1<-[1..8], x2<-[1..8],
x3<-[1..8], x4<-[1..8], x5<-[1..8],
x6<-[1..8], x7<-[1..8], x8<-[1..8],
safeH [x2,x3,x4,x5,x6,x7,x8] x1]
safeH xs e = if length xs == 1 then head xs
else e /= safeH (tail xs) (head xs)
and the error message is:
y.hs:1:42:
No instance for (Num Bool) arising from the literal `1'
Possible fix: add an instance declaration for (Num Bool)
In the expression: 1
In the expression: [1 .. 8]
In a stmt of a list comprehension: x1 <- [1 .. 8]
[1 of 1] Compiling Main ( y.hs, interpreted )
Failed, modules loaded: none.
The if ... then ... else ...
expression in safeH
is not well-typed:
safeH l e = if length l == 1 then head l
else e /= safeH(tail l)(head l)
The then
branch is incorrectly returning a numeric type, while the else
branch is returning a boolean type Bool
, as I think you intended.
You should add type signatures to all your top-level functions as a way of documenting what your code does, organizing your thoughts, and making errors easy to understand; the error message here is needlessly confusing because GHC infers that your code is returning some Num
type thing from the first branch, and so when the second branch returns Bool
GHC complains about the wrong thing: there being no instance of Num
for the Bool
type).
You should also read about pattern matching on lists, and take a look at the implementation of length
and think about why it's not the best way to implement your function here.
So instead of using length
and head
, start with this framework:
safeH :: [Int] -> Int -> Bool
safeH [n] e = -- the case for a 1-length list
safeH (n:ns) e = -- ???
When you get something working then try redefining it where the base case is the empty list []
.