Paalon
Paalon

Reputation: 83

How to solve the ambiguous type variable error in Haskell

I want to implement the following function to calculate $(-1)^n / (2n + 1)$ for an integer $n$ in Julia into Haskell.

# Julia

powersign(n) = ifelse(n % 2 == 0, 1, -1)

leibniz_term(n) = powersign(n) / (2n + 1)

println(leibniz_term(10)) # 0.047619047619047616

I write

-- Haskell

powersign 0 = 1
powersign 1 = -1
powersign n = powersign (rem n 2)

leibniz_term n = (powersign n) / (2 * n + 1)

main = print (leibniz_term 10)

but this gives the following errors.

$ ghc -o leibniz_hs leibniz.hs
[1 of 1] Compiling Main             ( leibniz.hs, leibniz.o )

leibniz.hs:9:8: 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 13 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the expression: print (leibniz_term 10)
      In an equation for ‘main’: main = print (leibniz_term 10)
  |
9 | main = print (leibniz_term 10)
  |        ^^^^^^^^^^^^^^^^^^^^^^^
...

Probably, I need to add type annotations to somewhere but I don't know how to do it. How to modify the code to work correctly?

Upvotes: 0

Views: 263

Answers (1)

lsmor
lsmor

Reputation: 5063

Note that rem works for Integer-like numbers, so powersign should be applied to those (In haskell named Integral type class). Whereas, division (/) is real number division. The compiler cannot know if n in leibniz_term is Integer-like or Real-like. In haskell you should explicitly convert between number types.

powersign 0 = 1
powersign 1 = -1
powersign n = powersign (rem n 2)

leibniz_term n = fromIntegral (powersign n) / (2 * fromIntegral n + 1)

main = print (leibniz_term 10)

Haskell's Numerical Hierarchy uncomplete history

In haskell you have regular number types: Int, Integer, Float and Double

All of them instantiate the Num Type Class. Meaning that they can perform

(+), (-), (*), signum, negate, ... (and some others)

Then division is different, you have Integral Type class to perform integer division: quot, rem, etc.... Members of this type class are Int and Integer

And Fractional type class to perform real-number divison: /. Members of this type class are Float and Double

To perform math operations like cos, sin, log, etc... you Have the Floating type class which members are Float and Double

Coercion is done via fromIntegral, which transform Int and Integer to any other numerical type. Transforming from Double or Float back to Integral is done using common truncate, ceiling, etc...

You have another numerical type called Rational, which is literally a ration between Intergers. There are some other numerical classes like RealFrac, RealFloat. You can get more info here: https://wiki.haskell.org/Converting_numbers and https://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html

Upvotes: 1

Related Questions