Search code examples
haskelltypestype-systems

How to figure out the type if it is ambiguous type?


I am a Haskell beginner and I am having some trouble understanding this. I have 2 functions defined in a file like this:

expr n x = (x ^ n)/(fact n)


fact n
  | n == 0 = 1
  | otherwise = n * fact (n - 1)

But when I try to run say expr 3 2 , I keep getting an error like this:

*Main> expr 3 2

<interactive>:31:1: error:
    • Ambiguous type variable ‘a0’ arising from a use of ‘print’
      prevents the constraint ‘(Show a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instances exist:
        instance Show Ordering -- Defined in ‘GHC.Show’
        instance Show Integer -- Defined in ‘GHC.Show’
        instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
        ...plus 22 others
        ...plus 19 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In a stmt of an interactive GHCi command: print it

I checked the types for the various expressions and I see this:

*Main> :t (/)
(/) :: Fractional a => a -> a -> a
*Main> :t (^)
(^) :: (Integral b, Num a) => a -> b -> a
*Main> :t 3 ^ 6
3 ^ 6 :: Num a => a
*Main> :t fact
fact :: (Eq p, Num p) => p -> p
*Main> :t fact 3
fact 3 :: (Eq p, Num p) => p
*Main> :t 9 / 6
9 / 6 :: Fractional a => a

But I cannot figure out what types to give my functions to avoid this. I tried giving my fact function a type like this since (/) expects Fractional:

fact :: (Fractional a) => Int -> a

But if I try giving my function types, the file doesn't even load in ghci. I can post the error message I get from attempting to load my file with types if that helps.

If I try to add type to the show used when evaluating the expression, that doesn't work either:

*Main> expr 3 2 :: String

<interactive>:37:1: error:
    • No instance for (Fractional String) arising from a use of ‘expr’
    • In the expression: expr 3 2 :: String
      In an equation for ‘it’: it = expr 3 2 :: String

<interactive>:37:6: error:
    • No instance for (Num String) arising from the literal ‘3’
    • In the first argument of ‘expr’, namely ‘3’
      In the expression: expr 3 2 :: String
      In an equation for ‘it’: it = expr 3 2 :: String
*Main> expr 3 2 :: Integer

<interactive>:38:1: error:
    • No instance for (Fractional Integer) arising from a use of ‘expr’
    • In the expression: expr 3 2 :: Integer
      In an equation for ‘it’: it = expr 3 2 :: Integer

Solution

  • As mentioned in the comments, operator /, just like for + - *, forces its two operands to have the same type (and that's also the type of the result). Operator ^ is an exception, and its result has to have the same type as its left operand. Note that for floating-point types, you also have the ** exponentiation operator à la Fortran.

    Rules are explained in more detail in this tutorial.

    Unfortunately that means that mixed-mode arithmetics is somewhat less easy to get in Haskell than in some well-known imperative languages. If need be, conversion function fromIntegral :: (Integral a, Num b) => a -> b can be used. It gives the compiler license to insert some appropriate conversion.

    For the present situation, if a broad type signature is desired, it can be achieved for example like this:

    {-#  LANGUAGE  ScopedTypeVariables  #-}
    {-#  LANGUAGE  ExplicitForAll       #-}
    
    fact :: Integral nt => nt -> nt
    fact n = if (n <= 0)  then  1  else  n * fact (n - 1)
    
    expr :: forall nt ft.  (Integral nt, Fractional ft) => nt -> ft -> ft 
    expr n x = (x ^ n) / ((fromIntegral (fact n)) :: ft)
    
    

    Testing under ghci:

    $ ghci
    GHCi, version 8.6.5: http://www.haskell.org/ghc/  :? for help
     λ> 
     λ> :load q65254539.hs
    ...
    Ok, one module loaded.
     λ> 
     λ> expr 2 3
     4.5
     λ> expr 2 pi
     4.934802200544679
     λ> 
     λ> expr 3 (4::Double)
     10.666666666666666
     λ>