1
media :: (Num a) => [a] -> a
media [] = 0
media lst = (head lst) + media (tail lst)

This is a working function that goes through a number list and sum each element with the following element.

media2 :: (Num a) => [a] -> a
media2 str = (media str) / (length str)

This second function was supposed to get that sum and divide it by the length of the list, thus getting the arithmetic mean of the list. BUT the compiler returns me this

src/Main.hs@6:29-6:39Could not deduce (a ~ Int)
from the context (Num a)
bound by the type signature for media2 :: Num a => [a] -> a
at /home/app/isolation-runner-work/projects/32614/src.207/Main.hs:6:1-39
`a' is a rigid type variable bound by
the type signature for media2 :: Num a => [a] -> a
at /home/app/isolation-runner-work/projects/32614/src.207/Main.hs:6:1
In the return type of a call of `length'
In the second argument of `(/)', namely `(length str)'
In the expression: (media str) / (length str)

I don't understand what I am doing wrong, can someone please tell me?

2 Answers2

4

The length function always returns an Int, so you are trying to divide a (Num a) => a by an Int. The fromIntegral function will convert the Int into any Num type:

media2 :: (Fractional a) => [a] -> a
media2 str = (media str) / (fromIntegral $ length str)

EDIT

Just a couple of words about some insightful comments:

  1. Your media function is just the Prelude's sum.
  2. I'll assume you don't always want an Integral average, so I've changed the constraint on media2 to be Fractional instead of Num. This is because / has the type (/) :: (Fractional a) => a -> a -> a. Alternatively, you could use

    media2 :: (Integral a) => [a] -> a
    media2 str = (media str) `div` (fromIntegral $ length str)
    

    but you'll always get an integral average, which is probably not what you want.

jwodder
  • 54,758
  • 12
  • 108
  • 124
crockeea
  • 21,651
  • 10
  • 48
  • 101
  • 3
    The nonintuitive bit for people coming from other languages is that `/` is not overloaded to work on `Int`s in `Haskell`. You either have to explicitly use integer division (using `quot` or `div`) or convert the numerator and denominator to something that implements `Fractional`. – rampion Jun 02 '14 at 03:57
  • 2
    The type for `media2` should be `Fractional a => [a] -> a`. `Num a` is insufficient. – rampion Jun 02 '14 at 03:59
2

You can use genericLength from Data.List:

The genericLength function is an overloaded version of length. In particular, instead of returning an Int, it returns any type which is an instance of Num. It is, however, less efficient than length.

It's type signature is

genericLength :: Num i => [a] -> i 

Usage:

import Data.List

media2 :: (Num a) => [a] -> a
media2 str = (media str) / (genericLength str)
Benesh
  • 3,398
  • 1
  • 18
  • 38