[TYPES] seeking correct term for a quasi-dependent type

Dan Doel dan.doel at gmail.com
Thu Jun 10 16:06:10 EDT 2010


On Thursday 10 June 2010 2:00:20 pm Norman Ramsey wrote:
> A new feature of the Glasgow Haskell Compiler, called 'indexed type
> families', makes it possible to write something that isn't a true
> dependent type but isn't parametrically polymorphic either.
> I'd like help figuring out what to call it.  Here's an
> example that is pretty close to what we're actually doing:
> 
>   outputFact :: forall a . a -> Info a
> 
> Although 'Info' has the same syntax as a parametric type
> *constructor*, it is actually a *partial* *function* on types:
> 
>   data Fact   = ...
>   data Middle = ...
>   data Last   = ...
>   newtype Label = Label Int
> 
>   -- here follows the definition of 'Info':
>   type family   Info a :: *
>   type instance Info Middle = Fact
>   type instance Info Last   = [(Label, Fact)]
> 
> How do I describe the function 'outputFact'?
> It's not a classic dependent function, because the type of the result
> doesn't depend on the value of the argument.  But the type of the
> result *does* depend on the static *type* of the argument.
> 
> And outputFact is less polymorphic than it might appear, since the
> bound type variable 'a' cannot be instantiated at any type, but only
> at a type in the domain of the type function 'Info'.
> 
> I'm a little reluctant to call 'outputFact' a "dependent function"
> or to say that it has a "dependent-function type", because those
> words mean something else.  But I'm at a loss as to how to describe it.
> 
> What sort of type is the type
> 
>   forall a . a  -> Info a

Are you certain functions with that type are not parametric? I can only think 
of one (or two, depending on seq):

  undefined -- \_ -> undefined

You will get errors if you try to instantiate 'a' to a type without an 
instance, but the definition is parametric. The only ways you can create non-
trivial functions of the type are:

1) Type classes

  class OutputFact a where
    outputFact :: a -> Info a

  instance OutputFact Middle where ...

2) GADTs

  data T a where
    M :: T Middle
    L :: T Last

  outputFact :: forall a. T a -> a -> Info a
  outputFact M x = ...
  outputFact L x = ...

But neither of those functions has the type 'forall a. a -> Info a'. The 
former has a constraint signaling its use of type-case, and the latter has the 
GADT parameter (I'm still not certain how to think about GADTs with regard to 
parametricity, though). And it is necessary to use one of these two methods 
(or write at a specific, concrete type), because without knowing what 'a' is, 
your function cannot know what 'Info a' is, so undefined will be the only 
value available for it to produce.

Info itself is not parametric (using a somewhat generalized notion of 
parametricity; the usual one applies to value-level functions, I believe), but 
neither is 'data Id a = Id a' if you really get into it.

--

As for how to describe things like Info, type families are like defining types 
by recursion. You see this in dependently typed languages. For instance, 
vectors can be defined by recursion over the size index:

  Vec : Type -> Nat -> Type
  Vec A z     = Unit
  Vec A (s n) = A * Vec A n

the oddities are that:

1) type families are open and partial
2) type families are using recursion over *types*, whereas you can't do that 
(directly) in most dependently typed languages, since types themselves aren't 
defined by induction, though you could define an inductive type of codes to 
recurse over.

This isn't unique to type families, though, because classes are the same way: 
open, partial and defined by recursion over the structure of types; they're 
just for defining values that way, rather than types (hence why they're one of 
the ways to write outputFact above).

-- Dan


More information about the Types-list mailing list