views:

514

answers:

4

I'm having an issue I want to learn more about, and how to avoid. I've got this code

len :: (Num r ) => [a] -> r
len [] = 0
len xs = 1 + len ( tail xs )

avg :: (Num t) => [t] -> Double
avg xs = ( sum xs ) / ( len xs )

Which renders the following error

len.hs:6:9:
    Couldn't match expected type `Double' against inferred type `t'
      `t' is a rigid type variable bound by
          the type signature for `avg' at len.hs:5:12
    In the expression: (sum xs) / (len xs)
    In the definition of `avg': avg xs = (sum xs) / (len xs)

Now, I know this error (thanks to irc.freenode.net#haskell) is a result of the division function

(/) :: (Fractional a) => a -> a -> a

However, I don't know what to do. My avg function signature should have nothing to do with the division opperators quirks (requiring Fractional typeclass). So, I'm left thinking the right way to overcome this is by casting to a type that impliments they Fractional typeclass but I have no idea how, or even if this is right? Any ideas?

+1  A: 

hhm the really problem is if it is an integral type you want to cast to a fractional type, but if it is an fractional type you want to leave it alone.

Try this

fromRational ((sum xs) % (leng xs))
upshaw
mauke in irc `17:14 < mauke> EvanCarroll: % requires integers` talking to him is too difficult., and I'd rather not ask him what he means by it. `:t (%)` isn't showing anything useful either.
Evan Carroll
@Evan: upshaw's code uses http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-Ratio.html -- It only works if the list elements are integers.
Stephan202
+4  A: 

You're overly constraining the type of avg. Use the more general version, avg :: (Fractional a) => [a] -> a

Don Stewart
my question would be, why is the stuff returned by `len` is part of the member to the `Fractional` typeclass, `:t sum [1,2,3]` and `:t len [1,2,3]` both show the result is only part of the `Num` typeclass. I'm confused how a function that requires its arguments to be apart of the `Fractional` typeclass can even be applied here.
Evan Carroll
EvanCarroll: The `Num` typeclass does not provide fractional division, but the `Fractional` typeclass does. Since `avg` uses `/` in its top-level calculation the type signature must reflect that. When you make this change the compiler knows to use floating point math in `sum` and `len`.
Michael Steele
+4  A: 

My avg function signature should have nothing to do with the division operator's quirks

Why is that? If you want to compute the average of a bunch of Integers, you'll have to divide at some point, so you'll have to convert them from Integers to the division-supporting type of your choice. A close look at the Num class (:i Num in ghci) reveals one problem with the type of avg: Num doesn't have enough methods — basically enough to add, multiply, and subtract. There's no guarantee that the number I give to avg can be converted to a Double at all.

If you enter an untyped function to compute an average, Haskell responds with the most generic type possible:

Prelude List> :type \x -> sum x / genericLength x
\x -> sum x / genericLength x :: (Fractional a) => [a] -> a

So that's the correct type of avg.

You might notice that avg [1,2,3 :: Integer] gives a type error. You can get around that by passing the argument to toRational or fromIntegral first, which use the Real and Integral instances for Integer, respectively.


Regarding the expression sum [1,2,3] / len [1,2,3]: It's true that a literal number like 1 has the type of Num a => a, which calls fromInteger on whatever type it turns out to be, but an expression like 1/2 has a more specific type of Fractional a => a, which you can see if you ask for the type of that expression instead of printing it out.

Something that might be helpful is :set -Wall in ghci, which turns on lots of warnings whenever a default type is chosen for you, giving a clue that the most generic type might no longer be correct.

jleedev
I've chosen this as the answer, (definitely gives the most effort) but I'd like a quick follow up with a resource of where I can find what the prelude has for types, and type-classes regarding number-like types. What types of integers am i precluding by requiring the inputs be apart of Fractional? I've never seen a type apart of this typeclass prior to doing `:t (/) and I'd like to know more about how it works. And, things magically join the class for the division
Evan Carroll
All those declarations are in the Prelude. Online reference here: http://www.haskell.org/ghc/docs/6.10.2/html/libraries/base/Prelude.html
Chuck
I once saw a directed acyclic graph showing the numeric type class hierarchy, but I can't find it now. Here's a gentle introduction: (http://www.haskell.org/tutorial/numbers.html). You can tell ghci to give you more info by using `:i (/)`, or :i on a type or class.
jleedev
A: 

I've encountered this problem. This best I've managed to do is have two functions for averaging: one for integrals and one for fractionals:

avgInt :: (Integral i, Fractional f) => [i] -> f
avgInt xs = fromIntegral (sum xs) / fromIntegral (length xs)

avgFrac :: (Fractional f) => [f] -> f
avgFrac xs = sum xs / fromIntegral (length xs)
Ollie Saunders