[Haskell-cafe] Using Product Algebraic types

Stefan Holdermans sholderm at students.cs.uu.nl
Sun Jul 4 16:18:35 EDT 2004


Crypt Master,

> data Population a = Population [(Fitness, a)]

  CM> Am I correct in assuming that your definition of
  CM> Popoulation is now using tuple and not product types ?
  
Yes, you are. If you really want to use a new product, you can of course:

> data FitnessProd a  = FProd Fitness a
> data Population' a  = Population' [FitnessProd a]

A pair, i.e. a binary tuple, is a product type itself, be it one with
special syntax. You can think of it as being defined by

< data (,) a b = (,) a b
  
  CM> If so it it better to use tuples?
  
As always: it depends. I guess it is a design matter. If your product really
represents some distinct entity, you might want to go for a new data type.
If your product is merely just a pair, using tuples is more straightforward.

  CM> You mentioned that I had applied the polymorphic type
  CM> "a" to Fitness, but but in the above example of person
  CM> and people they have done the exactly what I did ?
  CM> Used a space to seperate elements. So I am a little
  CM> confused as to why mine didnt work.
  
As I said, you encountered a kind error. You have Paul Hudak's book, haven't
you? In section 18.3 he explains how kinding works. You may want to read
about that.

To see where things went wrong, examine your definitions once again. First,
you defined Fitness to be a synonym of Integer.

> type Fitness = Integer

Integer is a data type that does not take any type arguments. You can think
of it as being defined by

< data Integer = ... | -2 | -1 | 0 | 1 | 2 | ...

A type constructor that does not take any type arguments to produce a type
is said to be of kind *. Here, Integer is of kind *, and, therefore, so is
Fitness.

Now consider, the following type:

> data Fork a = Fork a a

The type constructor Fork takes one type argument and therefore it has a
function kind: k -> *, for some k. From the right-hand side we can infer
that k is *, so the kind of Fork is * -> *. This means that the type
constructor Fork can be applied on a type of kind *, for example Integer.

> type ForkedInteger = Fork Integer

However, Fitness, which is of kind *, cannot be applied to any type
argument, so the following is illegal:

< type FitnessedInteger = Fitness Integer -- kind error!

This is exactly what you tried: applying Fitness to some other type.

  CM> Can I ask one question, I am not concerned with
  CM> performance at this point, but what sort of overhead
  CM> does a function like id have. It seems unneccesary to
  CM> me ( I am not critising your solution, I am vert
  CM> thankfull for your help in a large populations you
  CM> will  land up doing a fair amount of extra but simple
  CM> "reductions" ( I hope thats the right word. ) just to
  CM> "copy" the unkown "a". Or does it have to be a
  CM> function for some reason and so you had to use "id" ?

> rw (Population xs) =  Population (scanl1 f xs)
>                         where f (n, a) = (+ n) `pair` id
> pair       :: (a -> c) -> (b -> d) -> (a, b) -> (c, d)
> f `pair` g =  h
>                 where h (a, b) = (f a, g b)

Well, the unknown a-values should be transferred from the input list to the
output list, so there's not much choice here. In fact, the f function does
nothing more than

> f               :: (Fitness, a) -> (Fitness, a)
>                    -> (Fitness, a)
> f (m, _) (n, a) =  (n + m, a) 

which seems quite minimal.

HTH,

Stefan




More information about the Haskell-Cafe mailing list