Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get sum of int or integer in Haskell

Tags:

haskell

This function should work for both lists of Int and lists of Integer:

myFunc :: [Integer] -> [Char]
myFunc x =  if (sum x `mod` 2 ==1) then "odd" else "even"

But it only works on lists of Integers.

like image 764
Aryan Firouzian Avatar asked Jul 30 '17 02:07

Aryan Firouzian


2 Answers

Typeclasses provide a way to be generic about types (they're literally groups of types). You can use a typeclass constraint instead of the explicit type Integer, like this:

myFunc :: Integral a => [a] -> String
myFunc x = if (even (sum x)) then "even" else "odd"

What this will do is specify that it's a function from [a] to String where a is a type variable, and is constrained to be any type so long as it's a member of the Integral typeclass. Another way to say this is any type so long as it has an instance for the Integral typeclass. That means it has the typeclass's methods specified for that particular type.

The Integral typeclass is for types whose values are whole numbers (ie the integrals).

Happily both Int and Integer have an instance provided for Integral, so we can use that.

like image 60
Julian Leviston Avatar answered Sep 27 '22 19:09

Julian Leviston


Int and Integers are different types. They are both instances of the Integral typeclass, however, which has 'mod' as one of its functions.

In order to let your function work for things other than a specific type, what you want to do here is to say that the function, instead of being [Integer] -> [Char] or [Int] -> [Char], the type should be less restrictive than just one of those; it should be [a] -> [Char]. But if you declared that instance, it wouldn't compile, because of two things:

1) sum requires your x to be a list of numbers. That is,

sum :: Num a => [a] -> a; 

Num is another typeclass which requires any type that is an instance of Num to include a definition for (+), among other things; this allows sum to use addition to add all the numbers.

2) mod requires your sum of x to have a type that is of instance of Integral. So

mod (sum x) :: Integral a => a -> a

It's technically also required that the type is an instance of Num, since sum x must be, but the definition of Integral requires any instance of Integral to also be an instance of Real, which in turn requires it to be of type Num - essentially you get the requirement that the number be of a type with instance Num for free.

So, in the end, you need to let the first type be of a 'variable' (don't really know the term for it) type, but one that is required to be of type Integral:

myFunc :: Integral a => [a] -> [Char]
myFunc x =  if (sum x `mod` 2 ==1) then "odd" else "even"

Also, if you don't include the type declaration, (i.e., myFunc :: Integral a => [a] -> [Char]), the compiler will automatically fill in the blanks by assuming all of this for you. The type declaration is used to either clarify the type of a function, limit the applicability of a function, or clarify to the compiler what type a variable is when it's unable to infer the type for some reason. But you typically don't have to declare the type if you don't want to.

like image 20
Andrew Lei Avatar answered Sep 27 '22 19:09

Andrew Lei