Another polytypic function is size, which counts the number
of occurences of values of type in a structure of
type
.
size for L is just the standard list length function:
sizeL :: L
Int
sizeL Nil = 0
sizeL (Cons x xl) = 1 + (sizeL xl)
How about for structures of type G L (i.e.,
``standard'' rose trees)?
sizeGL :: G L
Int
sizeGL (Branch x xg) = 1 + sum (map sizeGL xg)
While this is clearly the right function, we needed to introduce the
functions sum and map.
Let's try B:
sizeB :: B
Int
sizeB NilB = 0
sizeB (Cons x xb) = 1 + (sizeB xb)
Well, it type checks, but it doesn't quite work right. The recursive
call to sizeB counts the number of Bush 's
in xb, not the number of
's. To implement
sizeB correctly, we need to generalize a little:
countB :: (
Int)
B
Int
countB ca NilB = 0
countB ca (Cons x xb) = (ca x) + (countB (countB ca) xb)
sizeB = countB ( x -> 1)
The function countB generalizes sizeB by taking an
argument ca that gives a count for occurences of values of
type . For the recursive call to countB, we
use countB ca to give a count for each occurence of type
B
in xb. Finally, sizeB is simply
a specialization of countB by giving each occurence of a
value of type
a count of 1.
With this generalization in mind, we can similary implement
countG:
countG :: (. (
Int)
Int)
(
Int)
G
Int
countG cf ca (Branch x xg) = (ca x) + (cf (countG cf cg) xg)
sizeG :: (
Int)
G
Int
sizeG cf = countG count (
x -> 1)
Finally, we can revisit L:
countL :: (
Int)
L
Int
countL ca Nil = 0
countL ca (Cons x xl) = (ca x) + (countL ca xl)
sizeL = countL ( x -> 1)
This exercise has demonstrated a common theme in polytypic programming. Often, when implementing some function, it makes more sense to implement a more general form of the function and obtain the target function as a specialization of the generalized function. To this end, in the next section, we'll implement an even more general function.
Question: how should countD and countC be implemented?