logoalt Hacker News

lackerlast Sunday at 4:13 PM7 repliesview on HN

Dependent types are very useful for some things. For example, I wish Python had the ability to express "a 10 x 5 matrix of float32s" as a type, and typecheck that.

The Curry-Howard correspondence, using dependent type system to have "proofs" be equivalent to "types", is powerful, but it can be really confusing. From a human point of view, there is a huge difference between "Your proof is wrong" and "You wrote a statement that fails typechecking".

Intuitively, when you make an error with types, it should be something fairly trivial that you just read the error and fix it up. When you make an error in a proof, it's understandable if it's very complicated and requires thought to fix. The natural UI is different.

So I agree with the author that the greatest benefit of Lean is not its typesystem per se, but its community. Specifically the fact that Lean's library of mathematics, mathlib, is organized like an open source community with pull requests. Whereas Isabelle's library of mathematics, the AFP, is organized like a scientific journal with referees.

I'm working on a dependent type system at the moment for a new theorem prover - Acorn, at https://acornprover.org - and my hope is to combine the good points of both Lean and Isabelle. It's nice that Lean has the power to cleanly express the simple dependent types that mathematicians often use, like vector spaces or quotients. But if you use dependent types too much then it does get complicated to debug what's happening.


Replies

Sharlinlast Sunday at 4:47 PM

> For example, I wish Python had the ability to express "a 10 x 5 matrix of float32s" as a type

To clarify, as long as 5 and 10 are constants, this is entirely possible in C++ and Rust^1, neither of which are dependently typed (or at most are dependently typed in a very weak sense). In general, neither can ensure at compile time that an index only known at runtime is in bounds, even if the bounds themselves are statically known. A proper dependently-typed language can prevent runtime out-of-bound errors even if neither the indices nor the bounds are known at type check time.

^1 And weakly in many other languages whose builtin array types have compile-time bounds. But C++ and Rust let user-defined generic types abstract over constant values.

show 9 replies
akstlast Sunday at 9:29 PM

One of the things I love about typescript is if your audacious enough you can kind of make some types like this (still a far cry from dependent types):

https://github.com/AKST/analysis-notebook/blob/main/lib/base... (Line 38)

It type checks, but I haven’t gotten a lot of mileage out of this (so far at least). I did something similar for vectors, which has been useful for when I destructure the elements, and it preserves that through vector operations.

https://github.com/AKST/analysis-notebook/blob/777acf427c65c...

The same is actually applies true for matrices, I wrote the multiplication to carry the new size into the output type

https://github.com/AKST/analysis-notebook/blob/777acf427c65c...

That said I mostly use this for square matrixes in web GL so you’re mostly working with square matrixes.

As an aside, this source is from a toy project largely more for leisure and fun, I don’t know if something like this would be suitable for a larger more data oriented project (at least in trend of how I represent data here).

aatd86last Sunday at 5:16 PM

> using dependent type system to have "proofs" be equivalent to "types"

Do you mean proposition as types? And proof has a program?

Or do you see it at somewhat a higher order, since values are proof for a type, and types can perhaps be proof at a higher level if they are first class citizen in the language?

(Which makes me think that dependent types is really a stairway between two type systems?)

Just wondering, since I had never personally seen it described in that fashion.

Other question: What is the function and runtime treatment of dependent types? Can they be instantiated on the spot by runtime values? A bit like defining/declaring functions that return arrays of runtime-known length? Does it involve two aspects of type checking? compile and runtime? Implementation-wise, doesn't it require too many indirections?

show 1 reply
creatayesterday at 10:34 AM

As other commenters have said, this doesn't need dependent types. Rust's const generics / C++'s non-type template parameters are enough.

Even in languages with dependent types, people tend to find it overly cumbersome to use them for actually prevent runtime errors like out-of-bounds access; they instead tend to save the dependent types for (1) data structure invariants that can be propagated easily, and (2) verification after the program has been defined.[0][1]

[0]: https://xenaproject.wordpress.com/2020/07/05/division-by-zer...

[1]: https://www.cs.ox.ac.uk/ralf.hinze/WG2.8/26/slides/xavier.pd... ("Programming with dependent types: passing fad or useful tool?" by Xavier Leroy in 2009; things might have changed since 2009)

slightwinderyesterday at 2:39 PM

> Dependent types are very useful for some things. For example, I wish Python had the ability to express "a 10 x 5 matrix of float32s" as a type, and typecheck that.

What do you mean? Every class is a type, so create your own class and control what goes in.

show 1 reply
BigTTYGothGFyesterday at 2:29 PM

> For example, I wish Python had the ability to express "a 10 x 5 matrix of float32s" as a type, and typecheck that.

Numpy arrays have been checkable by dtype for a little while now, and I think recent versions also support shape constraints.

show 1 reply
olivia-bankslast Sunday at 9:39 PM

I did a small small experiment in dependent typing for Python (and catching those errors before run time). It's a decently good fit, and with HM Type inference some neat things just fall out of the design.

But the real challenge is deciding how much of Python's semantics to preserve. Once you start enforcing constraints that depend on values, a lot of idiomatic dynamic behavior stops making sense. Curious what ways there are to work around this, but I think that's for a person better at Python than I :)