2
votes

I have just started learning Haskell and still haven't grasped Functional Programming. I need to create a polymorphic datatype whose type I don't know until one of the functions I've written is run. The program seems to want me to build a list of tuples out of a list, e.g.:

['Car', 'Car', 'Motorcycle', 'Motorcycle', 'Motorcycle', 'Truck'] would be converted to [('Car', 2), ('Motorcycle', 3), ('Truck', 1)].

Within a same list of tuples (a bag), all elements will be of the same type, but different bags may contain other types. Right now, my datatype declaration (I'm not sure if it's called 'declaration' in FP) goes:

type Amount = Int
data Bag a = [(a, Amount)]

However, when I try to load the module, I get this error:

Cannot parse data constructor in a data/newtype declaration: [(a, Amount)]

If I change data to type in the declaration, I get this error message for all functions:

Expecting one more argument to ‘Bag’
Expected a type, but ‘Bag’ has kind ‘* -> *’

Is there something I'm not grasping about FP or is it a code error?, and more importantly, how can I declare this in a way that actually allows me to load the module into GHCi?

1

1 Answers

8
votes

Defining a data type

This is not about functional programming itself. If you define a datatype (or newtype), in Haskell it needs a data constructor (for newtype there can only be one data constructor, and with one parameter). [(a, Amount)] is however not a good "name" for a data constructor (well you did not intend to use that as a data constructor anyway).

We can here write a data constructor like:

data Bag a = Bag [(a, Amount)]

and since here Bag contains (likely) one data constructor with one parameter, we can make it a newtype:

newtype Bag a = Bag [(a, Amount)]

The above however might not be necessary: you might want to declare a type alias with type:

type Bag a = [(a, Amount)]

in that case, you did not construct a new type, but you can write Bag a, and "behind the curtains", Haskell will replace this with [(a, Amount)].

Define functions with Bag

In case you now want to define a function that processes a Bag, you will need to specify the parameter a in the signature as well, for example:

count :: Eq a => [a] -> Bag a
count =  -- ...

Now it is clear that we transform a list of as, in a Bag of as.