简体   繁体   中英

Haskell functions with parameters different types

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.

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 (ie 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM