Nameable Type Parameters
                                      
                               Kevin Atkinson
                             [EMAIL PROTECTED]
   
                                       
                               The Basic Problem
                                       
   The basic problem with Haskell type system that it is impossible to
   make both Array and a list of tuple pairs a member of a class to
   lookup elements based on an index. It is also impossible to make both
   lists and arrays a member of of map class where items in the array
are
   treated as an associated pair. Although in practice this may not be a
   serious problem, it does put a series hinder on combing up with a
good
   clean abstraction of common data structures and algorithms in
Haskell.
   It is probably also one of the reasons Haskell received a B while Ada
   received an A in support for reuse in a controlled experiment to
judge
   the effectiveness of several different language for prototyping
   support.1
   
   One solution within Haskell is to use vague classes:
   
     class Find c i e where
       find :: i -> c -> e
     
     class Map a b c d where
       map :: (a -> b) -> c -> d
     
     instance Eq i => Find [(i,e)] i e where ...
     instance Map a b [a] [b] where ...
     
     instance Find (Array i e) i e ...
     instance Map (i,e) (j, f) (Array i e) (Array j f) where...
     
   However this solution has several problems:
   
   1.
          When used with a function like show it will lead to an
          unresolved overloading because Haskell can't figure out the
          return type.
   2.
          The instance declaration are unnecessary ugly.
   3.
          The map functions does not promise to return a container of
the
          same type based on the class declaration.
          
   Another solution within current Haskell is to make a new data type:
   
     data MyArray c (i,e) = MyArray c
     myarray :: Array i e -> MyArray (Array i e) (i,e)
     myarray a = MyArray a
     
   which will solve the problem of vague classes but will introduce a
new
   problem, manly that writing the Map class such as
   
     class Map c a b where
       map :: (a -> b) -> c a -> c b
     
   will not allow a map to be defined over a MyArray where the element
   types are not the same as the container type will also change.
   Defining the map instance for Array like so
   
     instance Map MyArray (Array i e) (i,e) (j,f) where ...
     
   will force j and f to be the same type of i and e respectfully. In
   order allow the contents type to change the map function will have to
   have a signature of
   
     map :: ((i,e) -> (j,f)) -> (MyArray (Array i e)) (i,e)
                             -> (MyArray (Array j f)) (i,e)
     
   which is not allowed as (MyArray (Array i e)) is the container type
   and it changed when the content types changed. Thus the map function
   will have to have have to have a vague signature such as in the
   original example. This defeats the whole purpose of defining a new
   type. Defining a new type also is not transparent to the end user
   which defeats the whole purpose of coming up with an abstraction.
   
                           Nameable Type Parameters
                                       
   Nameable type parameters is simply a way to attach labels to existing
   types. These labels can then be used to resolve overloading in a much
   more flexible way than Haskell currently can.
   
   To attach the a label to a type simple define it using the syntax
   
     assign ::= label atype = atype'
     label ::= valid uppercase Haskell identifier
     atype ::= valid Haskell type
     atype' ::= atype
     
   For example the Array class can have an Inx, El, and Con type label
   attached to it with the commands:
   
     Inx Array i e = i
     El Array i e = e
     Con Array i e = (i,e)
     
   Multiple assign statements may be given for the same label. A type
   label is then used by extending the valid Haskell type syntax to:
   
     type ::= simple-type label-type
     simple-type ::= [single-type ]+
     label-type :: = [label: type']+
     single-type ::= type-name | type-var
     type-name ::= valid uppercase Haskell identifier
     type-var ::= valid lowercase Haskell identifier
     type' ::= type
     
   (Function, List and Tuple types will also work however for the
purpose
   of this explanation, they will be ignored as it should be easy to
   expand the grammar to support them.)
   
   If the kind of simple-type is * then look for an assign with a
   matching label, and a matching atype and bind type' to atype' if it
   can. If it can't it will keep searching. If the kind of simple-type
is
   * -> * than look for either an assign with the same label in which
the
   atype has a kind of * -> * or has at least two single-types. If the
   atype has two single-types drop the last single-type when trying to
   find a match. Once a match is found, complete the type by applying
the
   dropped type and try to bind type' to atype' if it can. If it can't
   keep searching. Do a similar thing if the kind is * -> * -> * but
drop
   the last two single-types. Etc...
   
   For example the type el in ``Array El:el'' will match the assign
   statement ``El Array i e = e'' because the kind of Array is * -> * ->
   * and the assignment statement has at least three single-types. The
   type-var el will then be assigned the type for the last parameter of
   Array. So the statement ``Array E:el'' is really like saying ``Array
_
   el''. Multiple type labels may also be specified. The type ``Array
   El:el Inx:el'' would just be another way to write ``Array ix el.''
The
   beauty of the nameable type parameters system is that it can
represent
   types which can not normally be expressed Haskell such as ``Array
   Con:c''.
   
   Atype and possibly atype' should also be allowed to have type labels
   in it, however I have not worked out the details of how it would
work.
   
                  The Solution with Nameable Type Parameters
                                       
   Using Nameable Type Parameters the problem presented in section 1 can
   easily be solved.
   
     class Find c i e where
       find :: i -> c Inx:i El:e -> e
     
     class Map c a b where
       map :: (a -> b) -> c Con:a -> c Con:b
     
     Con [a] = a
     Inx [(i,e)] = i
     El  [(i,e)] = e
     
     Con Array i e = (i,e)
     Inx Array i e = i
     El  Array i e = e
     
     instance Eq i => Find [] i e where ...
     instance Map [] a b where ...
     
     instance Find Array i e ...
     instance Map Array (i,e) (j,k) where ...
     
   And it has none of the drawbacks that the solution in section 1 has.
   
                                  Conclusion
                                       
   I believe that nameable type parameters provide an very elegant
   solution to a very nasty limitation in Haskell. Please let me know
   what you think by emailing me at [EMAIL PROTECTED] or sending email
   the Haskell mailing list at [EMAIL PROTECTED] An html, text, TeX,
   dvi, ps, and LyX version of this document is available at
   http://metalab.unc.edu/kevina/ntp/.
     _________________________________________________________________
   
    Footnotes
    
   ... support.1
          Paul Hudak & Mark P. Jones, Haskell vs. Ada vs.C++ vs. Awk vs.
          ... An Experiment in Software Prototyping Productivity, July
4,
          1994
     _________________________________________________________________
   
   
    1999-05-22
-- 
Kevin Atkinson
[EMAIL PROTECTED]
http://metalab.unc.edu/kevina/


Reply via email to