Why is Product Bounded?

133 Views Asked by At

http://learnyouahaskell.com/functors-applicative-functors-and-monoids :

Product is defined like this:

newtype Product a =  Product { getProduct :: a }  
    deriving (Eq, Ord, Read, Show, Bounded)

Why is Product forced to be Bounded?

From the same book, a few paragraphs below:

Its instance for Monoid goes a little something like this:

instance Num a => Monoid (Product a) where  
    mempty = Product 1  
    Product x `mappend` Product y = Product (x * y)

Eh? The only constraint is Num a! But Num in particular means Integer, and this is not bounded (unlike Int), AFAIK.

Let's test it then:

import Data.Monoid

numbers :: [Integer]
numbers = [1..100]

main = print (getProduct . mconcat . map Product $ numbers)

Let's see this code in action:

m@m-X555LJ:~$ runhaskell wtf.hs
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
m@m-X555LJ:~$ 

Works. Doesn't fail.

So what's the bound of Product? Is there any bound of Product?

Let's play again:

m@m-X555LJ:~$ ghci
GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
Prelude> minBound :: Int
-9223372036854775808
Prelude> maxBound :: Int
9223372036854775807
Prelude> import Data.Monoid
Prelude Data.Monoid> maxBound :: (Product Integer)

<interactive>:4:1: error:
    • No instance for (Bounded Integer)
        arising from a use of ‘maxBound’
    • In the expression: maxBound :: Product Integer
      In an equation for ‘it’: it = maxBound :: Product Integer
Prelude Data.Monoid> maxBound :: Product

<interactive>:5:13: error:
    • Expecting one more argument to ‘Product’
      Expected a type, but ‘Product’ has kind ‘* -> *’
    • In an expression type signature: Product
      In the expression: maxBound :: Product
      In an equation for ‘it’: it = maxBound :: Product
Prelude Data.Monoid> maxBound :: (Product Int)
Product {getProduct = 9223372036854775807}
Prelude Data.Monoid> 
Leaving GHCi.
m@m-X555LJ:~$ 

It doesn't seem that Product is, by itself, Bounded. Int is; but maxBound :: (Product Integer) throws! IIUC Product deriving Bounded is a promise that maxBound is well-defined on Product. Apparently, not always.

So why is Product an instance of Bounded?

1

There are 1 best solutions below

0
melpomene On

Product is not an instance of Bounded (that would be a kind error, anyway). You're missing what deriving actually does.

There is a formal specification of derived instances in the Haskell report:

If T is an algebraic datatype declared by:

data cx => T u1uk = K1 t11t1k1 | ⋅⋅⋅ | Kn tn1tnkn
                     deriving (C1, …, Cm)

(where m ≥ 0 and the parentheses may be omitted if m = 1) then a derived instance declaration is possible for a class C if these conditions hold:

  1. C is one of Eq, Ord, Enum, Bounded, Show, or Read.
  2. There is a context cx′ such that cx′ ⇒ C tij holds for each of the constituent types tij.

[...]

Each derived instance declaration will have the form: instance (cx, cx′) => Ci (T u1uk) where { d } [...]

This means class constraints are automatically distributed to type parameters.

As explained in the section on Bounded:

The Bounded class introduces the class methods minBound and maxBound, which define the minimal and maximal elements of the type. For an enumeration, the first and last constructors listed in the data declaration are the bounds. For a type with a single constructor, the constructor is applied to the bounds for the constituent types. For example, the following datatype:

data  Pair a b = Pair a b deriving Bounded

would generate the following Bounded instance:

instance (Bounded a,Bounded b) => Bounded (Pair a b) where  
  minBound = Pair minBound minBound  
  maxBound = Pair maxBound maxBound

For Product, this means Product a is only an instance of Bounded if a is.