Different types in sum function - haskell

I'm new to Haskell so this could be a stupid question. I'm reading a book where it says :type sum is supposed to show sum :: (Num a) => [a] -> a. Instead of that the message is sum :: (Num a, Foldable t) => t a -> a. As I've seen in https://www.haskell.org/hoogle/?hoogle=Sum this difference is due to -I think- the existence of two different sum functions. Maybe it's something like polymorphism in Java, I'm just starting and I have no idea about how Haskell works.
So my questions are: how could I use the sum function which type is sum :: (Num a) => [a] -> a instead of the other one? Could you explain me what's going on here?

As I've seen in https://www.haskell.org/hoogle/?hoogle=Sum this difference is due to -I think- the existence of two different sum functions. Maybe it's something like polymorphism in Java
It is, indeed, polymorphism, though not in this way (see the P.S. at the end of this answer). Note that...
sum :: (Num a) => [a] -> a
... is already polymorphic in the type of the numbers being summed, so it would work with, for instance, lists of Integer and lists of Double. The difference between that and...
sum :: (Num a, Foldable t) => t a -> a
... is that this sum is also polymorphic in the type of the container:
GHCi> -- +t makes GHCi print the types automatically.
GHCi> :set +t
GHCi> sum [1 :: Integer, 2, 3]
6
it :: Integer
GHCi> sum [1 :: Double, 2, 3]
6.0
it :: Double
GHCi> import qualified Data.Set as S
GHCi> :t S.fromList
S.fromList :: Ord a => [a] -> S.Set a
GHCi> sum (S.fromList [1 :: Double, 2, 3])
6.0
it :: Double
For a container type to be used with sum, it has to have an instance of the Foldable class, which covers functions that, like sum, might be expressed as flattening the container into a list and then folding it in some way.
P.S.: Your book says something different than what you have seen because until quite recently the sum function in the Prelude used to have the less general, list-specific type, and your book predates the change. Having two different functions called sum, even if one is strictly more general than the other, would lead to a name clash (it was for a similar reason that I imported the Data.Set module qualified in the example above -- it is a good idea to do so because it defines a few functions such as map that clash with Prelude functions, and qualifying them with, say, S.map avoids any issues).

Related

Haskell syb Data.Generics not working as expected

On a ghci prompt everywhere (mkT (\x -> 2 * x)) (8.7, 21, "word") evaluates to (8.7, 42, "word").
I expected the 8.7 to be doubled as well. Why am I wrong?
This is the result of mkT monomorphizing its argument in this particular case, but it turns out there's no broader way to address the issue. mkT isn't doing anything wrong.
It's worth looking first at why everywhere (* 2) doesn't type-check.
ghci> :t everywhere
everywhere
:: (forall a. Data a => a -> a) -> forall a. Data a => a -> a
ghci> :t (* 2)
(* 2) :: Num a => a -> a
ghci> :t everywhere (* 2)
<interactive>:1:13: error:
• Could not deduce (Num a) arising from a use of ‘*’
from the context: Data a
bound by a type expected by the context:
forall a. Data a => a -> a
at <interactive>:1:12-16
Possible fix:
add (Num a) to the context of
a type expected by the context:
forall a. Data a => a -> a
• In the expression: (*)
In the first argument of ‘everywhere’, namely ‘(* 2)’
In the expression: everywhere (* 2)
everywhere has a higher-rank type - the first forall a. is inside the parentheses. I kind of dislike documenting the type that way - it uses a as a type variable in two completely separate ways. But there are two different scopes, and that matters. What it's saying is that any function passed to it must be polymorphic over all instances of Data.
But the type of (* 2) doesn't match up there. It won't work with any instance of Data. It requires more - it requires that it be provided an instance of Num. So the error message dutifully reports that it can't deduce (Num a) from the context Data a. So this isn't going to work. The pieces don't fit together.
This is where mkT comes into play:
ghci> :t mkT
mkT :: (Typeable a, Typeable b) => (b -> b) -> a -> a
Its type is a bit funny. It looks almost like it does nothing at all, but Typeable is a funny class. mkT actually compares a and b for type equality, using those Typeable constraints. If they're the same, it applies the function you provided. Otherwise, it just acts as the identity function.
What it does when it's applied to a function is where things are going wrong for you:
ghci> :t mkT (* 2)
mkT (* 2) :: Typeable a => a -> a
It's still polymorphic in a, but the b it used to have has vanished. It had to pick a specific type b to work against, and it did that by defaulting to Integer. (See ghc's extended defaulting rules for details on how that works in ghci.) So...
ghci> mkT (* 2) 3.5
3.5
ghci> mkT (* 2) 7
14
ghci> mkT (* 2) (7 :: Int)
7
At the type level, mkT has to monomorphize its argument. That's the only way it can make use of the Typeable constraint when used in a context where a relevant variable no longer appears in its type.
(To tie the loop back to everywhere, the reason mkT (* 2) works as an argument to everywhere is because Data is a subclass of Typeable. The Data constraint implies that the Typeable requirement will be satisfied.)
So what can you do about this? Well, it's impossible to write it truly generically because of Haskell's open world assumption. Anywhere in the program, any type might be declared an instance of Num with arbitrary implementations of (*) and fromInteger. In order to work with everywhere, there would need to be some mechanism to go from knowing something is an instance of Data to looking up its Num instance. This just isn't possible at run time. Types have been erased. There may be some residues like Typeable dictionaries being carried around, but they don't provide any means to look up other instance dictionaries. And while you might be able to envision a language where that sort of lookup is possible, it actually would be very harmful to allow it in Haskell. It would invalidate the ability to reason about types parametrically, which would be a giant loss.
The best you can do is write transformation functions that work on multiple types:
ghci> let f = mkT (* (2 :: Int)) . mkT (* (2 :: Double)) . mkT (* (2 :: Integer))
ghci> f 5
10
ghci> f 2.7
5.4
ghci> f (9 :: Int)
18
ghci> f "hello"
"hello"
It's verbose and you can probably write something better by hand if you so desire. But it at least works, at least to some extent. And it doesn't require breaking foundational assumptions in the language design, which is always a bonus.
Here is a simplification of your case that doesn't use any Data stuff.
module MyModule where
dbl x = 2 * x
myId :: (a->a) -> a -> a
myId f = f
myDbl = myId dbl
Don't type this to the ghci prompt, rather, create a .hs file and load it.
Now check what type myDbl has.
Prelude > :l MyModule
[1 of 1] Compiling MyModule ( MyModule.hs, interpreted )
Ok, one module loaded.
*MyModule > :t MyModule.myDbl
MyModule.myDbl :: Integer -> Integer
Surprise! Why is it compiling at all? And why the weird types?
Because of the defaulting rules. (Basically, "if you don't know what to do with Num a, just use Integer"). Since myId cannot deal with dbl :: Num a => a -> a, Haskell allows it to take the Integer version.
Disable defaulting by adding default () at the top, and this module no longer compiles.
mkT is no different from myId in this respect.

What does " Non type-variable argument in the constraint" really mean?

For example:
map (+1) 2
in ghci yields
<interactive>:23:1: error:
* Non type-variable argument in the constraint: Num [b]
(Use FlexibleContexts to permit this)
* When checking the inferred type
it :: forall b. (Num b, Num [b]) => [b]
I've seen many questions similar to mine, but all seem only to answer what we can deduce from this (that the type of the second argument to map is wrong), and how to fix it - but not what error actually means . Where do things go wrong precisely?
The error arises during the type-deduction of your statement.
Since
(+1) is of type Num a => a -> a
2 is of type Num a => a
map is of type (a -> b) -> [a] -> [b]
We know that map (+1) has to be of type (Num b) => [b] -> [b], and therefore map (+1) 2 of type (Num b, Num [b]) => [b]. But [b] is not just a type-variable, it's List of some type variable, where list is a data constructor. In an alternative version of Haskell where no syntactic sugar for lists exists, we might write (Num b, Num (List b)).
This is a problem because by default, Haskell does not support non type-variable arguments for constraints. So the precise nature of the problem is not that Haskell doesn't know how to map over numbers - it's that it doesn't allow values of the type that our function call produces.
But that rule isn't strictly needed. By adding -XFlexibleContexts when calling ghci, types of the sort that our method produces are now allowed. The reason for this is that the literal 2 in Haskell doesn't really represent a number - it represents an object of type Num a => a, which is constructed from the Integral 2 using fromIntegral. So the statement map (+1) 2 is equivalent to map (+1) (fromIntegral (2::Integer)). This means that the literal "2" can represent anything, given the proper instantiation - including lists.
2 has the type Num a => a; we haven't specified what a is, except that it has to have a Num instance.
map (+1) has the type Num b => [b] -> [b]; we have specified what b is, except it has to have a Num instance.
When we determine the type of map (+1) 2, we are basically unifying Num a ~ Num b => [b].
2 :: Num a => a
map (+1) :: Num b => [b] -> [b]
map (+1) 2 :: (Num b, Num [b]) => [b]
And this is the problem. Num requires a type variable like a or b, not a polymorphic type like [b], as its argument.
Here’s an actual answer:
GHC tries to infer the types by itself, and failed, or in GHC lingo:
When checking the inferred type …
Basically the conflict is:
• GHC is happy to have any value as a parameter for map (+1), as long as it is compatible with its type. And map (+1) wants a list of numbers, since + wants two numbers and 1 already is one number, and map always wants a list of values compatible with that.
• And here’s the kicker: GHC is happy to have 2 be any type! Because to save you the hassle of always having to specify if a literal 2 is of a certain type, GHC just treats numeric literals as Integer and replaces it with fromInteger 2. So since fromInteger is from the class Num, 2 can be anything that implemented that class Num! So 2 could be a list too!
So GHC is stuck trying to fit those things together, and tells you:
“It needs to be some value, that is a number. … And where the list of those values is also a number!”
Or in Haskell:
it :: forall b. (Num b, Num [b]) => [b]
But there is no instance that makes lists numbers!
Or in GHC lingo:
Non type-variable argument in the constraint: Num [b]
That’s why you nowadays get this, yes definitely badly designed and confusing error message.
(Almost all GHC error messages are a cruel joke. The best thing you can do to understand them, is to read them bottom to top! And know all of Haskell’s type system freedoms and the GHC extensions that are forcing GHC to not make assumptions that would make these errors a much simpler sub-class of errors otherwise.)
Obviously, you’d normally just replace 2 with an actual list of some sort. But we’re not going to do that here. Since GHC wants crazy, GHC shall get crazy:
Silly resolution
So since it leaves us the option of making lists (of numbers) numbers, that’s what we shall do:
instance Num b => Num [b] where
(+) = zipWith (+)
(*) = zipWith (*)
abs = map abs
signum = map signum
fromInteger i = [fromInteger i]
-- or repeat [fromInteger i], if we’re evil. ;)
negate = map negate
So now, it works perfectly fine:
> map (+1) 2
[3]
Since 2 becomes fromInteger 2 :: Num a => [a], which puts 2 in a list ([2]), and then map (+1) is happy and turns it into [2+1]. Which evaluates to [3].
This possibility is why the error message wasn’t a much simpler
“Error: 2 is not a list, but map expects a list!”.

Why has Haskell decided against using `+` for string (list) concatenation?

Since I had trouble googling this question I thought I'd post it here.
I'm just interested in the logic behind it or wether it's just the creators' preference to use ++ instead. I mean, using a typeclass for strings that concatenates two strings (or rather lists) with + does not seem too hard to imagine.
Edit: I should add, that in Haskell one has to suspect reasons behind it, because + and ++ are functions defined in typeclasses, whereas in java the usage of + for string concatenation is just part of the language's syntax and therefor subject only to the creators preference/opinion. (The answers so far suggest that I was right about my suspicion.)
Also haskell comes from a mathematical background and is deeply influenced by mathematical syntax, so there might be deeper reasons than just preference/opinion.
typeclass for strings that concatenates two strings
Such a typeclass exists, although the operator isn't +, but <>:
Prelude> :m +Data.Monoid
Prelude Data.Monoid> "foo" <> "bar"
"foobar"
While ++ concatenates lists, the <> operator is more general, since it combines any two values of a given Monoid instance.
As other people have pointed out, + is reserved for Num instances. Why isn't the Monoid binary operator called +, then? Because addition is only one of infinitely many monoids; multiplication is another:
Prelude Data.Monoid> Sum 2 <> Sum 3
Sum {getSum = 5}
Prelude Data.Monoid> Product 2 <> Product 3
Product {getProduct = 6}
Choosing something like <> as 'the' monoidal operator is preferred exactly because it carries little semantic baggage.
Long story short, it would cause type troubles.
(+) is part of the Num typeclass:
class Num a where
(+), (-), (*) :: a -> a -> a
negate :: a -> a
abs :: a -> a
signum :: a -> a
fromInteger :: Integer -> a
x - y = x + negate y
negate x = 0 - x
And (++) :: [a] -> [a] -> [a].
It's easy to see the first problem: if we wanted (+) to work on list, we would have to implement (*), negate, abs, signum, and fromInteger for lists as well. Which is spurious.
If we decided to seperate (+) from the typeclass, and make a new typeclass, maybe called Plussable for (+), there would be too many typeclasses to keep track of, and simple expressions like 1 + 2*(2-1) would no longer be of type Num a => a, it would be of type (Plussable a, Timesable a, Minusable a) => a, and so on for each operation. It would be far too complicated.

Haskell: list of elements with class restriction

here's my question:
this works perfectly:
type Asdf = [Integer]
type ListOfAsdf = [Asdf]
Now I want to do the same but with the Integral class restriction:
type Asdf2 a = (Integral a) => [a]
type ListOfAsdf2 = (Integral a) => [Asdf2 a]
I got this error:
Illegal polymorphic or qualified type: Asdf2 a
Perhaps you intended to use -XImpredicativeTypes
In the type synonym declaration for `ListOfAsdf2'
I have tried a lot of things but I am still not able to create a type with a class restriction as described above.
Thanks in advance!!! =)
Dak
Ranting Against the Anti-Existentionallists
I always dislike the anti-existential type talk in Haskell as I often find existentials useful. For example, in some quick check tests I have code similar to (ironically untested code follows):
data TestOp = forall a. Testable a => T String a
tests :: [TestOp]
tests = [T "propOne:" someProp1
,T "propTwo:" someProp2
]
runTests = mapM runTest tests
runTest (T s a) = putStr s >> quickCheck a
And even in a corner of some production code I found it handy to make a list of types I'd need random values of:
type R a = Gen -> (a,Gen)
data RGen = forall a. (Serialize a, Random a) => RGen (R a)
list = [(b1, str1, random :: RGen (random :: R Type1))
,(b2, str2, random :: RGen (random :: R Type2))
]
Answering Your Question
{-# LANGUAGE ExistentialQuantification #-}
data SomeWrapper = forall a. Integral a => SW a
If you need a context, the easiest way would be to use a data declaration:
data (Integral a) => IntegralData a = ID [a]
type ListOfIntegralData a = [IntegralData a]
*Main> :t [ ID [1234,1234]]
[ID [1234,1234]] :: Integral a => [IntegralData a]
This has the (sole) effect of making sure an Integral context is added to every function that uses the IntegralData data type.
sumID :: Integral a => IntegralData a -> a
sumID (ID xs) = sum xs
The main reason a type synonym isn't working for you is that type synonyms are designed as
just that - something that replaces a type, not a type signature.
But if you want to go existential the best way is with a GADT, because it handles all the quantification issues for you:
{-# LANGUAGE GADTs #-}
data IntegralGADT where
IG :: Integral a => [a] -> IntegralGADT
type ListOfIG = [ IntegralGADT ]
Because this is essentially an existential type, you can mix them up:
*Main> :t [IG [1,1,1::Int], IG [234,234::Integer]]
[IG [1,1,1::Int],IG [234,234::Integer]] :: [ IntegralGADT ]
Which you might find quite handy, depending on your application.
The main advantage of a GADT over a data declaration is that when you pattern match, you implicitly get the Integral context:
showPointZero :: IntegralGADT -> String
showPointZero (IG xs) = show $ (map fromIntegral xs :: [Double])
*Main> showPointZero (IG [1,2,3])
"[1.0,2.0,3.0]"
But existential quantification is sometimes used for the wrong reasons,
(eg wanting to mix all your data up in one list because that's what you're
used to from dynamically typed languages, and you haven't got used to
static typing and its advantages yet).
Here I think it's more trouble than it's worth, unless you need to mix different
Integral types together without converting them. I can't see a reason
why this would help, because you'll have to convert them when you use them.
For example, you can't define
unIG (IG xs) = xs
because it doesn't even type check. Rule of thumb: you can't do stuff that mentions the type a on the right hand side.
However, this is OK because we convert the type a:
unIG :: Num b => IntegralGADT -> [b]
unIG (IG xs) = map fromIntegral xs
Here existential quantification has forced you convert your data when I think your original plan was to not have to!
You may as well convert everything to Integer instead of this.
If you want things simple, keep them simple. The data declaration is the simplest way of ensuring you don't put data in your data type unless it's already a member of some type class.

Haskell types frustrating a simple 'average' function

I'm playing around with beginner Haskell, and I wanted to write an average function. It seemed like the simplest thing in the world, right?
Wrong.
It seems like Haskell's type system forbids average from working on a generic numeric type - I can get it to work on a list of Integrals, or an list of Fractionals, but not both.
I want:
average :: (Num a, Fractional b) => [a] -> b
average xs = ...
But I can only get:
averageInt :: (Integral a, Fractional b) => [a] -> b
averageInt xs = fromIntegral (sum xs) / fromIntegral (length xs)
or
averageFrac :: (Fractional a) => [a] -> a
averageFrac xs = sum xs / fromIntegral (length xs)
and the second one seems to work. Until I try to pass a variable.
*Main> averageFrac [1,2,3]
2.0
*Main> let x = [1,2,3]
*Main> :t x
x :: [Integer]
*Main> averageFrac x
<interactive>:1:0:
No instance for (Fractional Integer)
arising from a use of `averageFrac ' at <interactive>:1:0-8
Possible fix: add an instance declaration for (Fractional Integer)
In the expression: average x
In the definition of `it': it = averageFrac x
Apparently, Haskell is really picky about its types. That makes sense. But not when they could both be [Num]
Am I missing an obvious application of RealFrac?
Is there way to coerce Integrals into Fractionals that doesn't choke when it gets a Fractional input?
Is there some way to use Either and either to make some sort of polymorphic average function that would work on any sort of numeric array?
Does Haskell's type system outright forbid this function from ever existing?
Learning Haskell is like learning Calculus. It's really complicated and based on mountains of theory, and sometimes the problem is so mindbogglingly complex that I don't even know enough to phrase the question correctly, so any insight will be warmly accepted.
(Also, footnote: this is based off a homework problem. Everybody agrees that averageFrac, above, gets full points, but I have a sneaking suspicion that there is a way to make it work on both Integral AND Fractional arrays)
So fundamentally, you're constrained by the type of (/):
(/) :: (Fractional a) => a -> a -> a
BTW, you also want Data.List.genericLength
genericLength :: (Num i) => [b] -> i
So how about removing the fromIntegral for something more general:
import Data.List
average xs = realToFrac (sum xs) / genericLength xs
which has only a Real constraint (Int, Integer, Float, Double)...
average :: (Real a, Fractional b) => [a] -> b
So that'll take any Real into any Fractional.
And note all the posters getting caught by the polymorphic numeric literals in Haskell. 1 is not an integer, it is any number.
The Real class provides only one method: the ability to turn a value in class Num to a rational. Which is exactly what we need here.
And thus,
Prelude> average ([1 .. 10] :: [Double])
5.5
Prelude> average ([1 .. 10] :: [Int])
5.5
Prelude> average ([1 .. 10] :: [Float])
5.5
Prelude> average ([1 .. 10] :: [Data.Word.Word8])
5.5
The question has been very well answered by Dons, I thought I might add something.
When calculating the average this way :
average xs = realToFrac (sum xs) / genericLength xs
What your code will do is to traverse the list twice, once to calculate the sum of its elements, and once to get its length.
As far as I know, GHC isn't able yet to optimize this and compute both the sum and length in a single pass.
It doesn't hurt even as a beginner to think about it and about possible solutions, for example the average function might be written using a fold that computes both the sum and length; on ghci :
:set -XBangPatterns
import Data.List
let avg l=let (t,n) = foldl' (\(!b,!c) a -> (a+b,c+1)) (0,0) l in realToFrac(t)/realToFrac(n)
avg ([1,2,3,4]::[Int])
2.5
avg ([1,2,3,4]::[Double])
2.5
The function doesn't look as elegant, but the performance is better.
More information on Dons blog:
http://donsbot.wordpress.com/2008/06/04/haskell-as-fast-as-c-working-at-a-high-altitude-for-low-level-performance/
Since dons has done such a good job at answering your question, I'll work on questioning your question....
For example, in your question, where you first run an average on a given list, getting a good answer. Then, you take what looks like the exact same list, assign it to a variable, then use the function the variable...which then blows up.
What you've run into here is a set-up in the compiler, called the DMR: the D readed M onomorphic R estriction. When you passed the list straight into the function, the compiler made no assumption about which type the numbers were, it just inferred what types it could be based on usage, and then picked one once it couldn't narrow the field down any more. It's kind of like the direct opposite of duck-typing, there.
Anyway, when you assigned the list to a variable, the DMR kicked in. Since you've put the list in a variable, but given no hints on how you want to use it, the DMR made the compiler pick a type, in this case, it picked one that matched the form and seemed to fit: Integer. Since your function couldn't use an Integer in its / operation (it needs a type in the Fractional class), it makes that very complaint: there's no instance of Integer in the Fractional class. There are options you can set in GHC so that it doesn't force your values into a single form ("mono-morphic", get it?) until it needs to, but it makes any error messages slightly tougher to figure out.
Now, on another note, you had a reply to dons' answer that caught my eye:
I was mislead by the chart on the last page of cs.ut.ee/~varmo/MFP2004/PreludeTour.pdf
that shows Floating NOT inheriting properties from Real, and I then assumed that
they would share no types in common.
Haskell does types differently from what you're used to. Real and Floating are type classes, which work more like interfaces than object classes. They tell you what you can do with a type that's in that class, but it doesn't mean that some type can't do other things, any more than having one interface means that a(n OO-style) class can't have any others.
Learning Haskell is like learning Calculus
I'd say learning Haskell is like learning Swedish - there are lots of little, simple things (letters, numbers) that look and work the same, but there are also words that look like they should mean one thing, when they actually mean something else. But once you get fluent in it, your regular friends will be amazed at how you can spout off this oddball stuff that makes gorgeous beauties do amazing tricks. Curiously, there are many folks involved in Haskell from the beginnings, who also know Swedish. Maybe that metaphor is more than just a metaphor...
:m Data.List
let list = [1..10]
let average = div (sum list) (genericLength list)
average
I'm amazed that after all of these years, no one has pointed out that Don Stewart's average doesn't work with complex numbers, while OP's averageFrac does work with complex numbers. Neither one is unambiguously superior to the other.
The fundamental reason why you can't write
average :: (Num a, Fractional b) => [a] -> b
is that it can be instantiated at a type like
average :: [Complex Double] -> Double
Haskell's numeric classes support conversions that are a little bit lossy, like Rational to Double, Double to Float, and Integer to Int, but don't support extremely lossy conversions like complex to real, or fractional to integral. You can't convert Complex Double to Double without explicitly taking (e.g.) the real part of it, which is not something that average should be doing. Therefore, you can't write average :: [Complex Double] -> Double. Therefore, you can't write average with any type that can be specialized to [Complex Double] -> Double.
The most Haskellish type for average is probably OP's averageFrac. Generally, functions that aren't dedicated to type conversion should be leaving the type conversion to the caller as much as possible. averageFrac will work with practically any numeric type, either directly or after coercion of the input list. The caller, being closer to the source of the data, is more likely to know whether it needs to be coerced or not (and if it doesn't know, it can leave the decision to its caller). In contrast, Don Stewart's average just doesn't support complex numbers, even with coercion. You'd either have to rewrite it from scratch or else call it twice with the real and imaginary projections of the list (and then write another wrapper for quaternions that calls it four times, etc.).
Yeah, Haskell's type system is very picky. The problem here is the type of fromIntegral:
Prelude> :t fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b
fromIntegral will only accept an Integral as a, not any other kind of Num. (/), on the other hand only accepts fractional. How do you go about making the two work together?
Well, the sum function is a good start:
Prelude> :t sum
sum :: (Num a) => [a] -> a
Sum takes a list of any Num and returns a Num.
Your next problem is the length of the list. The length is an Int:
Prelude> :t length
length :: [a] -> Int
You need to convert that Int into a Num as well. That's what fromIntegral does.
So now you've got a function that returns a Num and another function that returns a Num. There are some rules for type promotion of numbers you can look up, but basically at this point you're good to go:
Prelude> let average xs = (sum xs) / (fromIntegral (length xs))
Prelude> :t average
average :: (Fractional a) => [a] -> a
Let's give it a trial run:
Prelude> average [1,2,3,4,5]
3.0
Prelude> average [1.2,3.4,5.6,7.8,9.0]
5.4
Prelude> average [1.2,3,4.5,6,7.8,9]
5.25

Resources