0

As the questions states, I am having a little trouble with defining a function with parameters different types. (array of Num, two parameters Int and returning Int).

This is function title:

_sum_divide :: (Num a) => [a] -> (Int b) => b -> b -> b

And I get this error I cannot figure out

`Int' is applied to too many type arguments
In the type signature for `_sum_divide':
  _sum_divide :: Num a => [a] -> Int b => b -> b -> b

Sorry for the silly error, I am a noob with Haskell.

Thanks, have a good day/evening.

2
  • 4
    What is Int b supposed to be? And why do you have two constraint-arrows =>? Commented Mar 27, 2017 at 18:45
  • I actually don't really know 100% how constraint arrows work. a is supposed to be Num and b Int. Commented Mar 27, 2017 at 18:48

2 Answers 2

5

This seems to be a basic confusion between the concepts of type classes and of types. OO languages throw these all together, but in Haskell they are fundamentally different things.

  • A type is a set of values. For example, the type Bool contains the values False and True. The type Int contains the values 0, 1 ... 9223372036854775807 and their negatives.

  • A type class is a set of types. For example, the class Num contains the type Int, the type Double, the type Rational... and whatever type T of your own, if you just define an instance Num T.

Generally, types are used in function signatures just by naming them. For instance,

foo :: [Int] -> [Int]
foo = map (*3)

is a function accepting a list of Int numbers (i.e. values of type Int), and gives another such list as the result (wherein each entry is tripled).

There is no constraint at all in the signature of foo. I could actually add one, like

foo :: Num Int => [Int] -> [Int]

This would express that the function needs Int to be an instance of the Num class to work. Well, it does need that in order to be able to calculate *3, but the constraint is superfluous, because we know that Int is a Num instance, the compiler doesn't just forget about that.

Where constraints are really useful is in polymorphic functions. For example, the following function triples every entry in a list of numbers, and doesn't care what particular type the numbers have:

foo :: Num n => [n] -> [n]
foo = map (*3)

This notation with type variables like a is actually shorthand for

foo :: ∀ n . Num n => [n] -> [n]

meaning, for all numerical types n, the function foo maps lists of n-values to lists of n-values.

It's important that constraints are completely separate from the actual type specification in a signature. For instance, to specify for a polymorphic function [a] -> b -> b -> b that a should be a Num instance and b an Integral instance (the class of whole-number types, containing amongst other Int), you'd write

sum_divide :: (Num a, Integral b) => [a] -> b -> b -> b

Alternatively, if you really mean Int – that's just a single type, no reason to introduce a type variable for it.

sum_divide :: Num a => [a] -> Int -> Int -> Int

...although, you can still introduce the b variable if you like. You'll need an equational constraint (those are basically ad-hoc type classes containing only a single type)

{-# LANGUAGE TypeFamilies #-}

sum_divide :: (Num a, b ~ Int) => [a] -> b -> b -> b

Mathematicians would object about several levels of differences between types, sets and classes. Read my notion of “set” as just “collection of things”.

In more complicated settings you can actually mix constraints and types, but that's advanced stuff.

Sign up to request clarification or add additional context in comments.

Comments

2

The signature for a function that takes list of Nums and 2 int, and returns an int is:

_sum_divide :: (Num a) => [a] -> Int -> Int -> Int

The part before the thick arrow specifies the constraints. The part after it is where you use the constraints.

You had 2 main issues:

  • There should only 1 list of constraints in a signature.

  • Int isn't a Typeclass. (Num a) means a can be any type that supports the Num Typeclass. Int however is a concrete type, not a Typeclass, so (Int b) doesn't make sense.

2 Comments

Thank you very much, you've helped me a lot to understand.
@Marcus No problem. Just a suggestion: since types are such a prominent feature in Haskell, and understanding the type system is crucial for understanding error messages, Id go back over and review type signatures if I were you. It's well worth the investment of time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.