Fun with Type Functions

which will appear in the proceedings of Tony Hoare's 75th birthday celebration.

Abstract. Tony Hoare has always been a leader in writing down and proving
properties of programs. To prove properties of programs automatically,
the most widely used technology today is by far the ubiquitous type checker.
Alas, static type systems inevitably exclude some good programs
and allow some bad ones. This dilemma motivates us to describe some fun we've
been having with Haskell, by making the type system more expressive
without losing the benefits of automatic proof and compact expression.

Haskell's type system extends Hindley-Milner with two distinctive
features: polymorphism over type constructors and overloading
using type classes. These features have been integral to Haskell
since its beginning, and they are widely used and appreciated. More recently, Haskell has been enriched with
type families, or associated types,
which allows functions on types to be
expressed as straightforwardly as functions on values. This facility
makes it easier for programmers to effectively extend the compiler by
writing functional programs that execute during type-checking.

This paper gives a programmer's tour of type families as they are
supported in GHC today.

This Wiki page is a discussion page for the paper. If you are kind enough to read this paper, please help us by jotting down any thoughts it triggers off. Things to think about:

What is unclear?

What is omitted that you'd like to see?

Do you have any cool examples that are of a somewhat different character than the ones we describe? (If so, do explain the example on this page!)

You can identify your entries by preceding them with four tildes. Doing so adds your name, and the date. Thus:

i have dealt with all the comments and fixed all the noted problems. I
have a few questions about several suggestions though. I should remark
first that the complete code discussed in the paper is available,
presently in our darcs repository. I guess Simon has not decided of a
site to host the online version of the paper with the Appendices and
the code. Incidentally, code fragments in the paper are lifted
straight from the working code, using the remarkably useful
\VerbatimInput.

I was writing a generic finite map a while ago and determined that the generic memoized trie was better in almost all cases; it was simpler semantically and didn't have a significant performance difference. Then you have "type Map k v = Table k (Maybe v)". Is it worth calling out this special case in its own section?

Also, in respose to ChrisKuklewicz, I think the type for "cons" is correct, but perhaps one instance should be given as an example.

To Ryan Ingram: Just to double-check: you are saying that the
implementation of generic finite maps as
"type Map k v = Table k (Maybe v)" is faster that the one given in Sec
3.3? That is quite interesting!

Dave Menendez 16:52, 14 May 2009 (UTC) On page 11, you refer to a "specialised instance for Table Int that uses some custom
(but innite!) tree representation for Int." Was this meant to be Integer? Surely any tree representation for Int would be large but finite.

Peter Verswyvelen and I have been working on some type family fun to give us generalised partial application (even to the point of being able to cope with giving arguments, but not a function). I don't know if it really makes any interesting point that you didn't already in the paper, but it's certainly fun...

To Beelsebob: I'm afraid the code does not account for the most
interesting case: a function that takes a dynamic value and returns
a static result. So you need to deal with functions of the type
V a -> B b or B a -> V b. The literature on partial evaluation
describes this issue in detail. Our tagless-final paper (Sec 4.2 of
the the journal version, Delaying binding-time analysis) has a short
explanation, too.

End of section 2.2, I think "cons :: a -> [b] -> [ResTy a b]" should be "cons :: a -> [b] -> ResTy a b"

To Chris Kuklewicz, regarding the problem with footnote 9. That is an
odd problem that I could not reproduce. It seems xpdf lets me cut
and paste the URL in question without introducing stray spaces. BTW,
the type was correct, as Ryan Ingram described. We have implemented
his suggestion so to remove the confusion.

Why do you say "Obviously, we want to declare algebraic data kinds, ..."?
What's obvious about that? Many of us think that's the wrong way, and you should instead provide a way to lift ordinary data type to the kind level.

I was really fascinated by section 5.2 where you track state in the types using a parameterized monad. However, the example code you use is rather underwhelming since it can be implemented by much simpler means. If there's only a fixed number of locks then they can be tracked using a fixed tuple and the whole type functions business is a bit superfluous (albeit still nice). To really reap the benefits of the machinery you set up you ought to have a function for creating new locks dynamically. Here's an example of how it can be done:

In order for this to work nicely we need a new run function as well. I've used an ordinary type class to check that all locks are unlocked, since this really is a predicate on the state and not a function.

To Josef Svenningsson: indeed the variable number of locks would have
been sexier but it creates the problem of locks `leaking' out of scope
(e.g., returned as the result of runNew and then used within another
runNew computation, with disastrous results). In short, we need
regions. Chung-chieh Shan and I have indeed implemented such a system,
with a parameterized monad to track the state of the variable number of
resources (file handles in our case). Please see Sec 6 of our
Lightweight Monadic Regions paper. We used functional dependencies for
type functions. Replacing functional dependencies with type functions
is straightforward. Yet the staggering complexity of the code in Sec 6
will remain. I'm afraid this makes the example too complex for this
paper; rather than attracting users to type functions we would scare
all of them away.

It would be very nice if you published a bundle or repository somewhere containing the Haskell source from the paper. At the very least it would be nice with a comment on which version of GHC one should have and what flags are required. The reason I'm asking is that I had a bit of trouble with this. For instance, just saying {-# LANGUAGE TypeFamilies #-} didn't enable type equality constraints in the parser. I had to add ScopedTypeVariables which felt rather arbitrary.