Reputation: 128
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.
Upvotes: 0
Views: 3449
Reputation: 120751
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.
Upvotes: 5
Reputation: 45816
The signature for a function that takes list of Num
s 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.
Upvotes: 2