Nathan Kronenfeld
Nathan Kronenfeld

Reputation: 513

Differences between compiled code and ghci in Haskell

I have the following code:

-- defined externally in a module that compiles just fine
-- normal :: (RandomGen g, Random r, Floating r, Ord r) => r -> r -> g -> (r, g)
-- poisson :: (RandomGen g, Random r, Floating r, Ord r) => r -> g -> (Integer, g)
-- binomial :: (RandomGen g, Random r, Floating r, Ord r) => r -> g -> (Bool, g)
data Foobar = Foobar { n :: Double, p :: Integer, b :: Bool } deriving (Show)

randomFoobar :: (RandomGen g) => g -> (Foobar, g)
randomFoobar g0 = let (n, g1) = normal 10.0 1.0 g0
                      (p, g2) = poisson 5.5 g1
                      (b, g3) = binomial 0.5 g2
                  in (Foobar n p b, g3)

When I try to compile this, I get a host of errors, starting with

Foobar.hs:8:33: error:
    • Could not deduce (Random r0) arising from a use of ‘poisson’
      from the context: RandomGen g
        bound by the type signature for:
                   randomFoobar :: forall g. RandomGen g => g -> (Foobar, g)
        at Foobar.hs:6:1-49
      The type variable ‘r0’ is ambiguous
      These potential instances exist:
        instance Random Integer -- Defined in ‘System.Random’
        instance Random Bool -- Defined in ‘System.Random’
        instance Random Char -- Defined in ‘System.Random’
        ...plus four others
        ...plus 29 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the expression: poisson 5.5 g1
      In a pattern binding: (p, g2) = poisson 5.5 g1
      In the expression:
        let
          (n, g1) = normal 10.0 1.0 g0
          (p, g2) = poisson 5.5 g1
          (b, g3) = binomial 0.5 g2
        in (Foobar n p b, g3)

When I type the my randomFoobar function directly into ghci, it works fine.

I'm very new to Haskell, and completely flumoxed by this - anyone know what is going on here? Why is ghci different than the compiler here?

Upvotes: 3

Views: 116

Answers (1)

GHCi enables the ExtendedDefaultRules extension by default, which causes a default type to be chosen for some ambiguous types instead of just throwing an error. To make your code work everywhere, the best solution is to add a type annotation that makes the type unambiguous. The ambiguity in this case is that numeric literals are polymorphic. 5.5 could be a Float, a Double, a Rational, etc. Since at the end you just get a Bool, type inference isn't able to figure out which one you want, since any would be valid. Using (5.5 :: Double) instead of just 5.5 will do it, assuming Double is the type you want.

Upvotes: 6

Related Questions