Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

For readers wondering why this is, there are a few things at play here. I preface my explanation by saying that the benefit of type classes vastly outweigh issues like the above example. Also if I put the above example in my work project I immediately get a warning about the exact issue, so it's not like it is a foot gun or anything like that. Anyhow:

0. Integer is arbitrary precision while Int is bounded, machine dependent (eg. 32 or 64 bit). They are both instances of the Num type class as well as the Integral type class as we'll see later.

1. Numbers without explicit type signatures are overloaded (aka. constraint polymorphic):

  λ> :t 1
  1 :: Num p => p
where p can be any type that has a Num constraint, like Integer or Int.

2. As per https://www.haskell.org/onlinereport/decls.html#sect4.3.4 we have

  default (Integer, Double)
as concrete types for numbers to default to in expressions without explicit type signatures to guide inference.

3. The type of the list index operator is:

  λ> :t (!!)
  (!!) :: [a] -> Int -> a
where the index is a concrete Int type.

Right, so in the above example if we check the type of 7^7^7`mod`5`mod`2

  λ> :t 7^7^7`mod`5`mod`2
  (7^7^7`mod`5`mod`2) :: Integral a => a
it is still overloaded (Integral), ie. can be either Integer or Int. Now in the first case there's nothing to concretise the type thus we are defaulting to Integer as per the defaulting rule. In the second case the usage of (!!) concretise the type to an Int. As 7^7^7 is big it does not fit in an Int (overflows). Compare:

  λ> 7^7^7`mod`5 :: Integer
  3
  λ> 7^7^7`mod`5 :: Int
  2
The mystery is now solved. Side note: if we do

  default ()
to prevent GHC defaulting we'll get a type error and we will be forced to specific a type. We can also say:

  λ> ( (7^7^7`mod`5`mod`2)==1, [False,True]!!fromInteger((7^7^7`mod`5`mod`2)) )
  (True,True)


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: