It was drawn to my attention that there is an active Reddit thread about the future of dependent types in Haskell. (Thanks for the heads up, @
thomie!) Instead of writing a long response inline in Reddit, it seems best to address the (very knowledgeable, respectful, and all around heartening) debate here.
When can we expect dependent types in GHC?
The short answer: GHC 8.4 (2018) at the very earliest. More likely 8.6 or 8.8 (2019-20).
Here is the schedule as I see it:
- GHC 8.2: Clean up some of the lingering issues with
-XTypeInType
. As I will be starting a new job (Asst. Prof. at Bryn Mawr College) this fall, I simply won’t have the opportunity to do more than some cleanup work for the next release. Also, quite frankly, I need a release cycle off from the challenge of putting in a large new feature. Polishing up-XTypeInType
for release took probably an extra full month of unexpected work time! I don’t regret this in the slightest, but I could use a cycle off.
- GHC 8.4: This depends on what other research opportunities come up in the next year and how much more attention
-XTypeInType
needs. If all goes well this fall and I can get a few publications out in the next year (certainly possible – I have several in the works), then I could conceivably start primary implementation of-XDependentTypes
next summer. The odds that it will be in a state to merge for 8.4 are slim, however. - GHC 8.6: We’re now talking about a real possibility here. Assuming I start the implementation next summer, this would give me a year and a half to complete it. I desperately wish to avoid merging late in the cycle (which is what made
-XTypeInType
so stressful) so perhaps merging soon after GHC 8.4 comes out is a good goal. If this slips, GHC 8.8 seems like quite a likely candidate.
Regardless of the schedule, I have every intention of actually doing this work.
One major oversight in the schedule above: I have completely discounted the possibility of collaborators in coding this up. Do you wish to help make this a reality? If so, let’s talk. I’ll admit that there may be a bit of a hill for an outside collaborator to climb before I really start collaborating in earnest, so be prepared to show (or create!) evidence that you’re good at getting your hands dirty in the greasy wheels of GHC’s typechecker without very much oversight. I’ve encouraged several of you on Trac/Phab – you know who you are, I hope. For others who have not yet contributed to GHC: you’re likely best served starting smaller than implementing dependent types! But let’s talk anyway, if you’re interested.
What is the design of dependent types in Haskell?
I expect to hand in my dissertation in the next two weeks. While I am developing it in the public eye (and warmly welcome issues to be posted), there is no publicly available PDF build. Building instructions are in the README. I will post a built PDF when I hand in my draft to my thesis committee. I will be defending on September 1 and will likely make some revisions (as suggested by my committee) afterward.
Readers here will likely be most interested in Chapters 3 and 4. Chapter 3 will contain (I’m still writing it!) numerous examples of dependent types in Haskell and how they might be useful. Chapter 4 presents the design of dependent types in Haskell as a diff over current Haskell. This design is not yet up to the standard of the Haskell Reports, mostly because it is unimplemented and seems not worth the effort of formalization until we know it is implementable. For the overly curious, Chapter 5 contains a new intermediate language (to replace GHC Core) and Chapter 6 contains the type inference algorithm that will deal with dependent types. Happy summer reading!
Responses to particular comments on the Reddit thread
@
elucidatum: How radical of a change and how much of a challenge will it be to refactor existing codebases?No change is necessary. All code that currently compiles with
-XTypeInType
will compile with-XDependentTypes
. (The only reason I have to set-XTypeInType
as my baseline is because of the parsing annoyance around*
, which must be imported to be used with-XTypeInType
.) Any refactoring will be around how much you, as the Haskell author, wish to take advantage of dependent types.@
jlimperg: Pervasive laziness in Haskell means that we like to use a lot of coinductive types. But this is really annoying for proof purposes because coinduction, despite the nice duality with induction, is a lot less pleasant to work with.Yes, this is true. My approach is, essentially, to pretend that types are inductive, not coinductive. One consequence of this decision is that proofs of type equality will have to be run. This means that including dependent types will slow down your running program. Sounds horrible, doesn’t it? It doesn’t have to, though.
Suppose you have a function
proof :: ... -> a :~: b
. The functionproof
provides a proof that typea
equals typeb
. If this function terminates at all, it will always produceRefl
. Thus, if we knew that the function terminated, then we wouldn’t have to run it. We can’t know whether it terminates. But you, the programmer, can assert that it terminates, like this:{-# RULES "proof" proof ... = unsafeCoerce Refl #-}
Now, GHC will replace any use ofproof
withRefl
directly. Note that GHC still type-checks your proof. All thisRULE
does is assert termination.“But,” you say, “I don’t want to have to merely assert termination! If I wanted to assert correctness instead of prove it, I wouldn’t use dependent types.” My response: “Touché.” Haskell indeed is less powerful than those other dependently typed languages in this regard. Nevertheless, by using dependent types in Haskell, you still get a whole lot more compile-time guarantees than you get without dependent types. You just don’t get termination. You thus have a choice: “prove” termination at runtime by actually running your proofs, or assert it at compile time and keep your dependently typed program efficient, and still with lots of guarantees. Recall that we Haskellers have never proved termination of anything, ever, so not proving termination of a function named
proof
shouldn’t be all that alarming.Note: If
RULES
such as the one above become pervasive, perhaps a compiler flag can make them automatic, effectively (and concisely) assuming termination for all proofs in a module.@
jlimperg: Proving is hardYes, it is. Typechecker plugins may help here. It is easy enough, however, to implement dependent types without this advanced support. As we work through the consequences of dependent types in Haskell, I’m confident the community (including me) will come up with ways to make it easier.
@
jlimperg: As is well-known, a dependent type system is inconsistent (i.e. everything can be proven) unless all computations terminate, which is obviously not the case for general Haskell.Yes, this is true. Dependent types in Haskell will be inconsistent, when we view Haskell as a logic. Dependent types will still remain type-safe however. (This is because we run the proofs!) I just wish to point out here that
@
jlimperg suggests a syntactic check for termination: this, sadly, will not work. Haskell has too many ways for a computation to diverge, and a syntactic check can rule out only general recursion and partial pattern matches. Haskell also has infinite data types, non-strictly-positive datatypes,TypeRep
(which can be abused to cause a loop),Type :: Type
, and likely more back doors. I’d love to see a termination checker for Haskell, but I’m not holding my breath.@
jlimperg: This point is very speculative, but I strongly dislike the current flavour of ‘almost-dependent’ type-level programming in Haskell.So do I. Singletons are an abomination. I hate them. These are gone with my design for dependent types, and I think the resulting language has the niceties we all want in a dependently typed language (modulo termination checking).
@
dogodel: I think it will take a while for the change to percolate into better design. … I think the most immediate benefit will be for (no surprise) expressive DSL, which are actually quite common in any modest codebase, but maybe not the “core” of the project.Agreed completely. It will take time for us to figure out the best way to use dependent types.
@
sinyesdo: The best summary I can offer is that “totality” is really really important for DT languagesThis is true for those other dependently typed languages, but not for Haskell. See my response to the first of
@
jlimperg’s points quoted here.@
ccasin: The main reasons to care that your programming language is total are to make the type system consistent as a logic and to make type checking decidable. But we’ve already given up both these things in Haskell, and it’s possible to have dependent types without them.Agreed in full, and with
@
ccasin’s full post.@
jmite: If you want fully Dependent-Type types, why not use Idris, Agda, Coq, or F*?I’m in broad agreement with the responses to this point on Reddit: basically, that none of these languages have Haskell’s ecosystem or optimizing compiler. See also Section 3.3 of my dissertation.
@
tactics: What does “fully dependent types” even mean for something like Haskell? You would have to rework the core language entirely.Yes, precisely. This is Chapter 5 of my dissertation.
Conclusion
I hope this information helps. Do keep an eye out for my finished dissertation sometime in the next few months. And, as always, this is all a work in progress and no one should take anything as set in stone. If there’s a design decision you disagree with, please speak up!
This is interesting stuff! If you’re replacing GHC Core, are you planning to upgrade its names to use something like Bound?
No. GHC uses a consistent approach to naming across many of its structures, and changing this approach would be a major undertaking, quite separate from any revamping of Core. I’m afraid I have no informed opinion as to whether or not this change is something to pursue.
“One major oversight in the schedule above: I have completely discounted the possibility of collaborators in coding this up.”
I assume you meant _haven’t_ discounted the possibility of collaborating. 😉
No, I meant what I said there. But it’s clearly all ambiguous. What I meant was that, while writing the text above, I was discounting the possibility. In reality, I’m not discounting it — I’d love to chat with potential collaborators. It was perhaps not the best way of expressing my intent!
When you get to Bryn Mawr, make sure to get to know http://cs.brynmawr.edu/~dblank/ I met him some 15 years ago was I was an undergrad, but if he’s still cool, he’ll be a great guy to “talk shop” with.
Thanks for the tip, Boyd. I’ve already met Doug and am very much looking forward to working with him. In truth, I’m really quite excited about starting at Bryn Mawr — it really ticks all the boxes for me: lots of opportunities to have fun teaching; great research support; fantastic colleagues (at both Bryn Mawr and Haverford); and spitting distance from Penn, where I plan on maintaining all of my research connections and collaborations. As an added bonus, my family and I can easily continue all the friendships and connections we’ve made living in the Philly area for 5 years.
Will `TypeInType` become the singular approach to dependent types in haskell? I want to learn to use dependent types in haskell. I skimmed various articles, and different articles involve different GHC extensions to achieve dependent types.
I don’t know where to start. Can you recommend an entry point for someone who’s becoming an intermediate haskell programmer?
“Can you recommend an entry point for someone who’s becoming an intermediate haskell programmer?”
Not really. TypeInType is essentially a halfway point to getting full dependent types in Haskell. However, most of the work is under the hood. To do dependently-typed programming in Haskell, you still need singletons. There is a nice introduction to singletons here: https://blog.jle.im/entry/practical-dependent-types-in-haskell-1.html
You will still need lots of extensions, though. I hope this is helpful!
Pingback: Refinement Types and Dependent Functions Stable in Racket 6.11 – Pin by Vurdpress
What is the current status of this project?
Under active, if slow, development. There are a plethora of proposals at https://github.com/ghc-proposals/ghc-proposals/pulls to add bits and pieces of the syntax for dependent types, I have a small army of students who will hopefully be implementing some of these proposals (and other related improvements) this summer, and one of the accepted GSoC proposals is to implement dependent types in GHC Core. Some collaborators and I are also working out the details about how roles will interact with dependent types, with calls scheduled biweekly. So it’s all moving forward! I would wager that, somewhere, we take a small step forward daily, so I’m pleased to say this isn’t stalled at all — just a big project that will take a lot of time.
Realistically, we won’t have dependent types before 2020 (at the end of a yearlong research leave of mine, which I plan on spending the bulk of implementing this stuff).
Thanks for the update, looking forward. World really needs a decent language with dependent types. I think the current state of Haskell, with its gazillion extensions, many of which brings additional type-level features, is not satisfactory, as it frightens people.
It’s been another couple years since we’ve had any updates, and we’re now on GHC 8.8, is there any major notable progress? Doing some quick googling, it seems like there are bits and pieces of progress towards an improved type-level, but we still don’t seem much closer to a proper Dependent Haskell
Pingback: Can Haskell ensure a Functor (or other typeclasses) satisfies its law? - PhotoLens