Algebraic types and subclassing

Arjan van IJzendoorn arjanij@cs.kun.nl
Wed, 11 Mar 1998 12:04:48 +0100


Hello Nick,

>    You could define OSType as a record and define an instance of toString
>and fromString. This might very well be the best way to go, although I have
>to admit, the excessive usage of toString with all the standard string
>manipulation tools might be a pain.

I don't think that this is the way to go. Maybe much more overloading
in the standard environment makes things better, e.g.:

class SupportsStringOperations a where
  index  :: Int      a -> Char
  update :: Int Char a -> a
  etc.

The OSType can then be made an instance of this class as well as "normal"
strings. Even lists of characters can be made an instance. This would
make things more orthogonal, something Alan Grover was hoping for, I believe.

>    Second, (you essentially suggested this in an earlier posting..) is just
>to make OSType an ADT. Clean has no language level support for ADTs that I'm
>aware of, although existential types have some similarities.

You can make types abstract in Clean by not exporting the implementation
of the type. In a definition module you can write something like:

:: Stack a

push :: a (Stack a) -> Stack a

etc.

>    I propose an extension to Clean's existing type class system, such that
>constraints and invariants and the like can be defined in classes. Imagine,
>if you will, a class String. Now, imagine:
>
>instance String OSType
>asserts
>    ForAll o :: OSType
>        len o = 4
>    ForAll i in [1..4]
>        o.[i] <- [0..255]

Someone will look into this in the future, but it is unknown so far who
and when.

>Unfortunately, this example is not great, for several reasons. Since classes
>only define the types of functions, a Clean extended with the above feature
>would still need to re-implement all the String functions. The possible
>solutions to this problem are:
>    1. to expand classes so that they can actually implement functions, not
>just define the them, (this is similar to classes that are neither abstract
>nor concrete in OO languages);
>    2. allow instances or classes to inherit from other *instances*, (this
>resembles the ability to inherit from concrete classes in OO languages);
>    3. allow not just multiple parameter classes (coming in Clean 2.0?), but
>parameterLESS classes. Yes, this essentially identical to an instance, but
>you can *inherit* from them. This would eliminate the need for the instance
>construct altogether. This requires (1) and eliminates the need for (2).

This sounds very much like an object-oriented typing system. I must say
that, personally, I am very interested in combinations of OO with functional
languages, too. I will probably look into it during my PhD.

>- The ability to define functions of arity exceeding 1 in more convenient
>ways:
>    You can define:
>        Add :: Int Int -> Int
>        Add x = \y -> x + y

Not in Clean you can. The arity of the type has to be the same as the
arity of the definition. I often bump into this restriction, too.

>    Sure, you can do this by defining Add :: (Int Int -> Int), but that's
>not the same.

Why is this not the same? I always use this and it works fine (apart
from subtle uniqueness problems...)

>- The use of more classes in the standard library

I agree. See above.

>- Language level support for ADTs. Data hiding is pretty tricky without
>this. And you *can't* hide types without this.

Don't you like making ADT's through the use of the module system?

>- Make the language more orthogonal. Clean is already beautifully small, but
>I think it could be a bit smaller. An example is the case construct. Perhaps
>I'm missing something, but couldn't case be defined like:
>    case` :: a [(a, b)] -> b | Eq a
>    case` x l = snd (hd (filter (((==) x) o fst) l))

You can't bind variables in this way and you need equality on type a (not
needed when doing pattern-matching).

>- OK, this is a pipe dream, but I'd like to see first class types (i.e.,
>type can be passed as arguments to functions). This eliminates the need for
>a special construct for dynamic types, special constructs for parametered
>types (e.g., :: Parser s r :== [s] -> [([s],r)]), etc.

Your example can be expressed in Clean. I don't see what else you want.

>- Another pipe dream: reflection. I think reflection might be a useful
>feature in some contexts.

Why?

>- Support for all major platforms (Unix too!)

Do you volunteer to do the porting? :)

Greetings,
  Arjan