简体   繁体   中英

Haskell confusion about (Bits a) inferenced type error

I'm experimenting with some math functions and have come up with the following:

import Data.Bits

mulGF2n a b g = divModGF2n (mulGF2 a b) g
  where
    mulGF2 a b
      | a == zeroBits = zeroBits
      | otherwise     = xor (if testBit a 0 then b else zeroBits) (mulGF2 (shiftR a 1) (shiftL b 1))

divModGF2n a b = go a zeroBits
  where
    n      = log2 b
    log2 a = let x = shiftR a 1 in if x == zeroBits then 0 else 1 + log2 x
    go a q
      | r < 0     = (q, a)
      | otherwise = go (xor a (shiftL b r)) (q .|. bit r)
      where
        r = log2 a - n

They're Galois Field calculations, but what they do aren't important. Notice I've left out the type signatures.

GHCI tells me the following about the inferred types:

*Main> :t divModGF2n
divModGF2n :: (Bits t1, Bits t) => t -> t -> (t1, t)

*Main> :t mulGF2n
mulGF2n :: (Bits a, Bits t1, Bits t) => a -> t -> t -> (t1, t)

So far so good. I try to modify the mulGF2n function so that instead of returning a tuple of type (t1, t) , it only returns the second element of type t . I modify the function's first line from:

mulGF2n a b g = divModGF2n (mulGF2 a b) g

to:

mulGF2n a b g = snd $ divModGF2n (mulGF2 a b) g

Now, GHCI gives me this error:

Could not deduce (Bits a0) arising from a use of ‘divModGF2n’
from the context (Bits a, Bits b)
  bound by the inferred type of
           mulGF2n :: (Bits a, Bits b) => a -> b -> b -> b
  at polydiv.hs:(12,1)-(16,100)
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
  instance Bits Bool -- Defined in ‘Data.Bits’
  instance Bits Int -- Defined in ‘Data.Bits’
  instance Bits Integer -- Defined in ‘Data.Bits’
  ...plus one other
In the first argument of ‘snd’, namely
  ‘(divModGF2n (mulGF2 a b) g)’
In the expression: snd (divModGF2n (mulGF2 a b) g)
In an equation for ‘mulGF2n’:
    mulGF2n a b g
      = snd (divModGF2n (mulGF2 a b) g)
      where
          mulGF2 a b
            | a == zeroBits = zeroBits
            | otherwise
            = xor
                (if testBit a 0 then b else zeroBits)
                (mulGF2 (shiftR a 1) (shiftL b 1))

The same thing happens if I use instead mulGF2n abg = let (q, r) = divModGF2n (mulGF2 ab) g in r . What is the reason that it is okay with me returning the tuple but not the second element of the tuple? It might help if I knew what the type a0 referred to in the error, but it only complains about the type but doesn't tell me which one it is referring to.

I will explain the problem using a simpler example.

Consider this:

class C a where def :: (Int, a)

f :: (Eq a, C a) => Int -> (a, Bool)
f x = let (y,z) = def in (z, x==y)

The above function returns two values, one of type a (in class C ), and a Bool . Note that the second result is actually dependent on what a actually is. To see why, consider:

> instance C Char where def = (0, 'a')
> instance C ()   where def = (1, () ) 
> f 0 :: (Char,Bool)
('a', True)
> f 0 :: ((), Bool)
((), False)

Now, consider this:

> snd (f 0) :: Bool

This can not be correct: it should be either True or False depending on what a is used to call f . The compiler has no way to infer what this a should be, so it rejects the above program during type checking.

More in detail, it generates the following types:

f :: (Eq a, C a) => Int -> (a, Bool)   -- OK
f 0 :: (Eq a, C a) => (a, Bool)        -- OK
snd (f 0) :: (Eq a, C a) => Bool       -- NOT OK

The last type is invalid because a appears in the constraints but not in the type which follows them.

If you really want to do that, you have to provide a manually, eg

snd (f 0 :: (Char, Bool)) :: Bool       -- OK

In your code, you have

mulGF2n :: (Bits a, Bits t1, Bits t) => a -> t -> t -> (t1, t)

and if you project out the second component you build a function

g :: (Bits a, Bits t1, Bits t) => a -> t -> t -> t
g a b c = snd $ mulGF2n a b c

where t1 appears only in the constraints, so the type is invalid. If you wish to choose t1=t , then you must inform the compiler of your choice:

g :: (Bits a, Bits t) => a -> t -> t -> t
g a b c = y `asTypeOf` x
     where (x,y) = mulGF2n a b c

where the function asTypeOf is provided in the Haskell Prelude just for the purpose of making the types of y and x equal. Its definition is simply the following

asTypeOf :: a -> a -> a
asTypeOf x y = x

Note that the above could have the more general type a -> b -> a , yet it is defined with the above stricted type. This is done on purpose, so that the compiler is informed that both arguments have the same type.

(Another common way to do this is enabling the ScopedTypeVariables extension, but it's a bit overkill for this simple case.)

To see what's going on, first we'll separate log2 out of divModGF2n and give it a type signature. The result of log2 is any number.

log2 :: (Bits a, Num n) => a -> n
log2 a = let x = shiftR a 1 in if x == zeroBits then 0 else 1 + log2 x

Now let's look at divModGF2n

divModGF2n a b = go a zeroBits
  where
    n      = log2 b
    go a q
      | r < 0     = (q, a)
      | otherwise = go (xor a (shiftL b r)) (q .|. bit r)
      where
        r = log2 a - n

The second argument to go , q , never interacts with anything but itself. It starts out as zeroBits :: Bits a => a . It's calculated for the recursive step from q .|. bit r q .|. bit r . bit :: Bits a => Int -> a and (.|.) :: Bit a => a -> a -> a . We can't determine the type of q except by how it is used when it's returned by (q, a) . This is why there's an extra type variable t1 in the signature for divModGF2n .

:t divModGF2n
divModGF2n :: (Bits t1, Bits t) => t -> t -> (t1, t)

Now let's see what happens if we try to define a function to return just the remainder.

modGF2n :: Bits a => a -> a -> a
modGF2n a b = let (q, r) = divModGF2n a b
              in r

We get the following error.

Could not deduce (Bits a0) arising from a use of `divModGF2n'
from the context (Bits a)

What's going on is we can only determine the type of the quotient for divModGF2n from how it's used when it was returned. modGF2n doesn't use the quotient, so we can't determine its type. The compiler needs a Bits instance for this type to be able to use divModGF2n . That's why we get an error message.

As a programmer, we can observe that the remainder from divModGF2n didn't depend on the quotient. We can define modGF2n by providing a type that has a Bits instance for the quotient and it won't affect how the remainder is calculated.

{-# LANGUAGE ScopedTypeVariables #-}

modGF2n :: Bits a => a -> a -> a
modGF2n a b = let (q :: Bool,r) = divModGF2n a b
              in r

The t1 type variable in mulGF2n is completely unrelated to the arguments it is given. As a result, GHC doesn't know how to pick a type for it and it remains ambiguous.

Here is a smaller example of the same problem:

default ()

example :: (Num a, Num b) => (a, b)
example = (1, 2)

exampleFst :: Num a => a
exampleFst = fst example

(The default () is needed because GHC has special rules about how to resolve ambiguous Num types. This line allows us to turn those features off.)

We get an ambiguous type error because GHC doesn't know how to pick a Num instance for the b type variable in example . Since it isn't used anywhere else, it isn't given any clues to help it determine what type it should be. We can eliminate this error by constraining it to be a specific type with an explicit type signature:

{-# LANGUAGE ScopedTypeVariables #-}
exampleFst :: forall a. Num a => a
exampleFst = fst (example :: (a, a))

The ScopedTypeVariables extension tells GHC we want the a in the explicit type signature of the third line to be the same as the a in the type signature of exampleFst (this is enabled with the forall when this extension is turned on).

A similar approach can be used to solve your type error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM