1

I'm starting my journey into Haskell and running into my first issue:

In my Haskell script:

myList = [1, 2, 3, 4, 5, 6, 7]

average ns = sum ns `div` length ns

when i'm in the ghci repl, i get two different results:

  • if i type > average [1, 2, 3, 4] i get the expected value of 2
  • but if i try to use myList and type > average myList, i get the error "Couldn't match type ‘Integer’ with ‘Int’"

I understand (at least i think i do) the concept of not having variables, so myList is just a function that returns a "hardcoded" list everytime i call it.

How can i make this work, and why is it behaving like this?

André Alçada Padez
  • 10,987
  • 24
  • 67
  • 120

1 Answers1

3

length will return an Int whereas sum will return a number with the same type of the items in the list (here likely Integer).

You can work with fromIntegral :: (Integral a, Num b) => a -> b to convert a number of an Integral type to any Num type, for example thus an Int to an Integer.

We thus can implement this as:

average :: Integral a => [a] -> a
average ns = sum ns `div` fromIntegral (length ns)

Beause you make use of div :: Integral a => a -> a -> a will thus constrain the two operands and the result to the same type, and that type should be a member of the Integral typeclass.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • also, i see the usefulness of the first line where you clarify exactly what goes in and what comes out, but for this specific case, the second line is enough and works the same – André Alçada Padez Oct 24 '21 at 16:15
  • 3
    @AndréAlçadaPadez It's actually fairly simple: Haskell never changes the type of a variable. If `x` is an `Int`, it stays an `Int` and is never silently "promoted" to any other numeric type as it happens in some other languages. OTOH, numeric literals like `42` are polymorphic: their type will match what the context requires. Hence `double x = 1/2;` is zero in C (integer division, then promotion) but `let x :: Double ; x = 1/2` is 0.5 in Haskell since the literals are `Double`s. – chi Oct 24 '21 at 17:02
  • @chi, i was counting on that; coming from other languages though, i wouldn't expect it to be two different types as Integer vs Integral haha – André Alçada Padez Oct 24 '21 at 17:08
  • 2
    @AndréAlçadaPadez Haskell has types `Int`, `Integer`, `Int32`, `Int64`, `Word32`, etc. Instead `Integral` is a type class, a "set of types", not a single type. This is used (among others) to make `div` work on all the integral types without having to use separate functions `divInt, divInteger, ...`. – chi Oct 24 '21 at 17:16
  • 1
    @AndréAlçadaPadez: `Integral` is a typeclass, you can see it as a set of types that implement a certain set of functions, this looks quite similar to what an interface does in Java, C#, etc. – Willem Van Onsem Oct 24 '21 at 17:17