Christopher Jeris wrote:
> Hi everyone. I am a sometime O'Camler just learning Haskell. Type
> classes are fun and I like the expressiveness you get without grafting a
> whole "object system" onto your nice functional language. But sometimes
> they baffle me, as in the following.
>
> This function fails to typecheck:
> -- Determinant algorithm from Knuth 4.6.4(31).
> -- briefly: [x22 - (x21/x11)x12 ... x2n - (x21/x11)x1n]
> -- det x[ij] = x11 det [ ... xij - (xi1/x11)x1j ... ]
> -- [xn2 - (xn1/x11)x12 ... xnn - (xn1/x11)x1n]
> det :: (Ix a, Num b) => Array (a,a) b -> b
> det x | (i0,i1) /= (j0,j1) = error "det: square matrices only"
> | null (range (i0,i1)) = (fromInteger 1)::b -- ERROR is here
> | i0 == i1 = x!(i0,i0)
> | True = x!(i0,i0) * det x'
> where ((i0,j0), (i1,j1)) = bounds x
> i'0 = (range (i0,i1)) !! 1
> b' = ((i'0,i1), (i'0,i1))
> x' = accum (-)
> (array b' [(ij, x!ij) | ij <- range b'])
> [((i,j), (x!(i,i0) / x!(i0,i0)) * x!(i0,j))
> | (i,j) <- range b']
>
> Hugs98 (May, Hugs extended mode) gives the error
> ERROR "Matrix.hs" (line ...): Cannot justify constraints in type
> annotation
> *** Expression : fromInteger 1
> *** Type : b
> *** Given context : ()
> *** Constraints : Num b
>
> I wrote the offending clause as (fromInteger 1)::b because, when it was
> just (fromInteger 1), the inferred type of det had b bound equal to Num
> Double, which wasn't general enough to match my declared type. But as the
> constraint Num b is declared in the type I want det to have, I don't
> understand why the constraint is not found during type checking.
>
> Simpler functions such as
> test :: Num a => Bool -> a
> test False = (fromInteger 0)::a
> test True = (fromInteger 1)::a
> typecheck just fine.
>
> Can you show me what I am missing?
Let's take the last question first. The type variable `a' that you are trying to
use in `(fromInteger 0)::a' is not bound by the type signature as you seem to
believe. The type variables in the signature scope only ofer the signature.
So you are asking for `(fromInteger 0)' to have any type, whic is of couse impossible.
Back to your original problem. You should remove the `::b'. You problem is that
the type you have given is too general. You have declared the result to be Num,
but you are using `/' in the function. You cannot divide in Num, so replace Num
by Fractional.
--
-- Lennart