I have a small question about defining functions over types declared
with "newtype".  Consider the following:

   newtype MyList a = MyList [a]

   myMap1 :: (a -> b) -> MyList a -> MyList b
   myMap1 f (MyList []) = MyList []
   myMap1 f (MyList (x:xs)) =
      case myMap1 f (MyList xs) of MyList ys -> MyList (f x:ys)

   myMap2 :: (a -> b) -> MyList a -> MyList b
   myMap2 f (MyList xs) = MyList (myMap2' f xs)
   myMap2' f [] = []
   myMap2' f (x:xs) = f x : myMap2' f xs

   unMyList :: MyList a -> [a]
   unMyList (MyList xs) = xs

   myMap3 :: (a -> b) -> MyList a -> MyList b
   myMap3 f (MyList []) = MyList []
   myMap3 f (MyList (x:xs)) = MyList (f x : unMyList (myMap3 f (MyList xs)))

or even, with the recent proposal for an extension to guards,

   myMap4 :: (a -> b) -> MyList a -> MyList b
   myMap4 f (MyList []) = MyList []
   myMap4 f (MyList (x:xs))
      | MyList ys <- myMap4 f (MyList xs) = MyList (f x:ys)

Should any of these rather cumbersome ways of defining the standard
map over (MyList a) cause any more code than the standard definition
of map over lists?

Is there a more elegant way of defining map over (MyList a)?  (I am
aware that I could have used "map" in place of "myMap2'" but assume
for the moment that the function I am writing over (MyList a) has not
been defined over [a].)

I find it easy to tag a list to convert it to the type (MyList a), but
un-tagging (MyList a) to convert it back to [a] I find rather
cumbersome.

Perhaps there is no elegant solution to this, but as long as I can
rely on the above code generating no more work than necessary, I am
content.

Which of the above ways do people prefer?

-=GEM=-

PS. If anyone is wondering why I should want to use newtype, it comes
in very handy when defining implementations of ADTs that just use for
example a simple list representation.  Introducing an explicit tag via
a "data" construction would increase space and time usage.  Using a
"type" construction would not allow me to define instances of a class
for the ADT.



Reply via email to