Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding why a/b doesn't work, but fromInteger a / fromInteger b does

Tags:

haskell

In Haskell, this works:

ghci>5/2
2.5

Great. But if I assign 5 and 2 to variables..

Main> let a = 5
Main> let b = 2
Main> a/b
<interactive>:68:2:
    No instance for (Fractional Integer)
      arising from a use of `/'
    Possible fix: add an instance declaration for (Fractional Integer)
    In the expression: a / b
    In an equation for `it': it = a / b
Main>

I get errors up the wazoo. The only way I can get around it is by saying:

*Main> fromInteger a / fromInteger b
2.5
*Main>

What is going on with fromInteger? Why do I need it to make this work?

like image 231
CodyBugstein Avatar asked Dec 01 '22 21:12

CodyBugstein


2 Answers

It's the monomorphism restriction at work. The types of a and b get defaulted to Integer, which obviously can't be used with / since it only works on Fractional types.

You can fix this by adding a type annotation when defining a and b:

> let a = 5 :: Double
> let b = 2 :: Double
> a / b
2.5

or you can use decimal literals which will default to Double:

> let a = 5.0
> let b = 2.0
> a / b
2.5

This would not be a problem if these three lines were type checked together, as they would be in a compiled module, or if you had entered

let a = 5; b = 2 in a / b

However, when typed separately in GHCi, they are type checked one at a time, so the defaulting that is applied when evaluating let a = 5 picks Integer because at that point the only constraint on a is Num. It doesn't know about the Fractional constraint that we need in order to use / with it later.

like image 79
hammar Avatar answered Dec 04 '22 02:12

hammar


Prelude> :t 5 / 2            -- The type is inferred to be a fractional
5 / 2 :: Fractional a => a
Prelude> :t (/)              -- ...because the type of (/)
(/) :: Fractional a => a -> a -> a
Prelude> let x = 5
Prelude> let y = 2
Prelude> :t x                -- In GHC there are addditional type defaulting rules
x :: Integer                 -- Instead of Num a => a, a lone integral is typed as `Integer`
Prelude> :t y
y :: Integer
Prelude> :i Fractional       -- Notice that 'Integer' is not an instance of 'Fractional'
class Num a => Fractional a where
  (/) :: a -> a -> a
  recip :: a -> a
  fromRational :: Rational -> a
    -- Defined in `GHC.Real'
instance Fractional Float -- Defined in `GHC.Float'
instance Fractional Double -- Defined in `GHC.Float'

In brief? GHCi type-defaults your let-bound variables to Integer, which do not have Fractional instances (because Integers aren't fractions). In a Haskell program compiled via ghc the types would unify.

EDIT: I should add that I am trying to note how let x = 4 could be inferred as Double were it in a larger context, and not on GHCi. In response to Hammar's answer, it isn't just monomorphism, but also has to do with type defaulting. a and b can monomorphicly be Double, as in a GHC-compiled function, but because the combination of the monomorphism restriction and the line-by-line type inference we can't get either x :: Num a => a or x :: Double - both of which would have suited your needs.

like image 24
Thomas M. DuBuisson Avatar answered Dec 04 '22 01:12

Thomas M. DuBuisson