FtheBuilder
FtheBuilder

Reputation: 1437

Haskell - random (mkStdGen 0) - Why is it working without explicit type?

The type of the expression random (mkStdGen 0) is Random a => (a, StdGen), so I tried:

System.Random> random (mkStdGen 0) :: (Int, StdGen)
(9106162675347844341,1346387765 2103410263)
System.Random> random (mkStdGen 0) :: (Double, StdGen)
(0.9871468153391151,1346387765 2103410263)

But, why does the following work?

System.Random> random (mkStdGen 0)
(9106162675347844341,1346387765 2103410263)

How was it able to "guess" a type in this case?

Upvotes: 1

Views: 147

Answers (1)

Daniel Wagner
Daniel Wagner

Reputation: 153102

From the Haskell Report:

Ambiguities in the class Num are most common, so Haskell provides another way to resolve them—with a default declaration: default (t1 , … , tn) where n ≥ 0, and each ti must be a type for which Num ti holds. In situations where an ambiguous type is discovered, an ambiguous type variable, v, is defaultable if:

  • v appears only in constraints of the form C v, where C is a class, and
  • at least one of these classes is a numeric class, (that is, Num or a subclass of Num), and
  • all of these classes are defined in the Prelude or a standard library (Figures 6.2–6.3 show the numeric classes, and Figure 6.1 shows the classes defined in the Prelude.)

Each defaultable variable is replaced by the first type in the default list that is an instance of all the ambiguous variable’s classes. It is a static error if no such type is found.

Only one default declaration is permitted per module, and its effect is limited to that module. If no default declaration is given in a module then it assumed to be:

default (Integer, Double)

This almost explains the behavior, except that the class Random in the constraint Random a is not a subclass of Num from the Prelude; to explain this, we must consult the GHC documentation:

At the GHCi prompt, or with GHC if the -XExtendedDefaultRules flag is given, the following additional differences apply:

  • Rule 2 above [ed. note: this is the third rule in our list above] is relaxed thus: All of the classes Ci are single-parameter type classes.

  • Rule 3 above [ed. note: this is the second rule in our list above] is relaxed this [sic]: At least one of the classes Ci is numeric, or is Show, Eq, or Ord.

  • The unit type () is added to the start of the standard list of types which are tried when doing type defaulting.

And now we're a bit closer to an explanation, except that it seems that the second bullet point still isn't satisfied: Random is neither numeric nor one of the three listed acceptable alternatives. BUT ghci implicitly adds a call to print for non-IO actions (and even for IO actions first tries adding a call to print to see if things will type-check, falling back on the non-printing version only when that fails), and as a result we get an additional Show a constraint hidden in the type of our expression, and this finally explains why the defaulting rules may be used. Since there is no instance of Random for (), the default falls through to Integer.

Upvotes: 5

Related Questions