
Hi, after some playing around with monad transformers and starting to like those specialities of Haskell, I am currently really feeling thrown back by a simple problem: trying to write a sine-function... Here is the part of my code that is troubling me: fac :: Integer -> Integer fac n = product [1..n] term :: Double -> Integer -> Double term x n = (-1.0::Double)**(fromInteger n) * (x**(fromInteger (2*n + 1))) / (fromInteger (fac (2*n + 1))) The term function is supposed to be the direct translation of the formula of a term within the sum. But it isn't: it is actually cluttered with lots of type conversions, and I had a hard time figuring out how to make it work at all. I hope that this is not the easiest way to do that and I would appreciate any help on how to handle those type conversion issues... Thanks, Chris

On Sun, Jun 13, 2004 at 11:15:28AM +0200, Christian Hofer wrote:
fac :: Integer -> Integer fac n = product [1..n]
term :: Double -> Integer -> Double term x n = (-1.0::Double)**(fromInteger n) * (x**(fromInteger (2*n + 1))) / (fromInteger (fac (2*n + 1)))
Why do you have all those type annotations? Simply writing directly: fac n = product [1..n] term x n = -1 ** n * (x ** (2 * n + 1)) / fac (2 * n + 1) gives you functions for which are inferred the types (which you can of course also give explicitly if you want): fac :: (Enum a, Num a) => a -> a term :: (Floating a, Enum a) => a -> a -> a And the type variable a can then be instantiated for Double. If you really need to take an Integer parameter, you only need a single conversion: term' x n = term x (fromIntegral n) with the type: term' :: (Floating a, Enum a, Integral b) => a -> b -> a If all this looks confusing, then forget about polymorphism and just give exact types in the type annotations: fac :: Double -> Double fac n = product [1..n] term :: Double -> Double -> Double term x n = -1 ** n * (x ** (2 * n + 1)) / fac (2 * n + 1) term' :: Double -> Integer -> Double term' x n = term x (fromIntegral n) Hope this helps. Lauri Alanko la@iki.fi

Lauri Alanko wrote:
fac :: Integer -> Integer fac n = product [1..n]
term :: Double -> Integer -> Double term x n = (-1.0::Double)**(fromInteger n) * (x**(fromInteger (2*n + 1))) / (fromInteger (fac (2*n + 1)))
Why do you have all those type annotations? Simply writing directly:
fac n = product [1..n] term x n = -1 ** n * (x ** (2 * n + 1)) / fac (2 * n + 1)
gives you functions for which are inferred the types (which you can of course also give explicitly if you want):
fac :: (Enum a, Num a) => a -> a term :: (Floating a, Enum a) => a -> a -> a
And the type variable a can then be instantiated for Double.
Except that it's arguable that Double shouldn't be an instance of
Enum.
Really, this "solution" is relying upon a misfeature of the language;
one which won't work in the general case. Suppose that fac was a
different function, one which couldn't be defined as returning a
non-integral result without using an explicit (and conceptually
incorrect) type conversion.
--
Glynn Clements

Am 13.06.2004 um 12:25 schrieb Lauri Alanko:
Why do you have all those type annotations? Simply writing directly:
fac n = product [1..n] term x n = -1 ** n * (x ** (2 * n + 1)) / fac (2 * n + 1)
gives you functions for which are inferred the types (which you can of course also give explicitly if you want):
fac :: (Enum a, Num a) => a -> a term :: (Floating a, Enum a) => a -> a -> a
I didn't expect it to be that easy! Thank you for your detailed answer. I think, I just didn't expect [1..3.4] to work, but it actually does! And I see, I really have to give chapter 12.4 in HSoE a closer look... Chris

Christian Hofer wrote:
Here is the part of my code that is troubling me:
fac :: Integer -> Integer fac n = product [1..n]
term :: Double -> Integer -> Double term x n = (-1.0::Double)**(fromInteger n) * (x**(fromInteger (2*n + 1))) / (fromInteger (fac (2*n + 1)))
The term function is supposed to be the direct translation of the formula of a term within the sum. But it isn't: it is actually cluttered with lots of type conversions, and I had a hard time figuring out how to make it work at all. I hope that this is not the easiest way to do that and I would appreciate any help on how to handle those type conversion issues...
term :: Double -> Integer -> Double term x n = (-1.0::Double)**(fromInteger n) * (x**(fromInteger (2*n + 1))) / (fromInteger (fac (2*n + 1)))
In this specific instance, you probably want ^ (or possibly ^^)
instead of **; these have types:
(^) :: (Num a, Integral b) => a -> b -> a
(^^) :: (Fractional a, Integral b) => a -> b -> a
The difference is that ^^ supports negative exponents.
Using ^, term can be simplified to:
term :: Double -> Integer -> Double
term x n = (-1.0)^n * x^(2*n + 1) / fromInteger (fac (2*n + 1))
You can't get rid of the conversion in the denominator, because fac
returns an integer but / isn't defined on integers.
More generally, the core arithmetic operators (+,-,*,/) all require
that both arguments have the same type, and Haskell doesn't perform
implicit type conversions.
One option is to declare your own operators, e.g.:
(!+), (!-), (!*), (!/) :: (Real a, Real b, Fractional c) => a -> b -> c
a !+ b = realToFrac a + realToFrac b
a !- b = realToFrac a - realToFrac b
a !* b = realToFrac a * realToFrac b
a !/ b = realToFrac a / realToFrac b
Each arguments can be any instance of Real (i.e. any of the built-in
numeric types except for Complex), and the result will be
automatically cast to any instance of Fractional.
However, in practice you may end up getting a lot of errors due to
ambiguous types for intermediate results, so it might be better to
force the return type to e.g. Double.
--
Glynn Clements

Am 13.06.2004 um 12:44 schrieb Glynn Clements:
Using ^, term can be simplified to:
term :: Double -> Integer -> Double term x n = (-1.0)^n * x^(2*n + 1) / fromInteger (fac (2*n + 1))
(Further interesting information snipped...) Ok, I just didn't know this operator. This is actually exactly what I was hoping to be able to write. Thanks, Chris
participants (3)
-
Christian Hofer
-
Glynn Clements
-
Lauri Alanko