zw324
zw324

Reputation: 27180

Haskell: Why is there no type mismatch (and why does this compile)?

I was so sleepy that I wrote the following code (modified to just show the confusion):

fac s = take 10 [s, s `mod` 1 ..]

maxFactor x = if (s == [])
              then x
              else head    <-- this should be 'head x' instead of just 'head'
  where s = fac x

However, this load into ghci (and compiles) just fine. When I executed maxFactor 1, it complains (of course):

<interactive>:0:1:
    No instance for (Integral ([a0] -> a0))
      arising from a use of `maxFactor'
    Possible fix:
      add an instance declaration for (Integral ([a0] -> a0))
    In the expression: maxFactor 1
    In an equation for `it': it = maxFactor 1

<interactive>:0:11:
    No instance for (Num ([a0] -> a0))
      arising from the literal `1'
    Possible fix: add an instance declaration for (Num ([a0] -> a0))
    In the first argument of `maxFactor', namely `1'
    In the expression: maxFactor 1
    In an equation for `it': it = maxFactor 1

However, I don't understand this behavior:

fac's type is:

fac :: Integral a => a -> [a]

while maxFactor's type is:

maxFactor :: Integral ([a] -> a) => ([a] -> a) -> [a] -> a

Doesn't this mean the following:

  1. the first input to fac must be of typeclass Integral (e.g., fac 10);
  2. since in the definition of maxFactor, there is fac x, x must also be of typeclass Integral, thus, maxFactor's type would be begin with something like maxFactor :: (Integral a) => a ->... then something else? However, if that is the case, then why this code compiles since the return of maxFactor can be x or head, which when following this line of reasoning, does not have the same type?

What am I missing here?

Thanks for any inputs in advance!

Upvotes: 11

Views: 653

Answers (2)

Peter
Peter

Reputation: 1693

As you've noticed correctly, the use of function fac inside of maxFactor adds a Integral a constraint on the type of x. So x needs to be of type Integral a => a.

In addition, the compiler sees that maxFactor either returns head, which has type [a]->a or x. Therefore x must have the more specific type Integral ([a]->a) => ([a]->a), and so maxFactor has type

maxFactor :: Integral ([a] -> a) => ([a] -> a) -> ([a] -> a)

which is exactly what you got. There's nothing "wrong" with this definition so far. If you managed to write an instance of Integral type ([a]->a) you could invoke maxFactor without problem. (Obviously maxFactor wouldn't work as expected.)

Upvotes: 11

jberryman
jberryman

Reputation: 16635

in maxFactor the compiler infers that the function argument x necessarily has the same type as head (in your if clause). Since you also call fac on x (which in turn calls mod) it infers that x is also some Integral class type. Consequently, the compiler infers the type

maxFactor :: Integral ([a] -> a) => ([a] -> a) -> [a] -> a

that takes some head-like and integer-like argument... which is unlikely to be a real thing.

I think the fact that you can load that code into GHCi is more a quirk of the interpreter. If you were just compiling the code above, it would fail.

Edit: I guess the issue is that the type checker can make sense of your code, however there probably isn't any sensible way to use it.

Upvotes: 9

Related Questions