def Nat = Int: (|x| -> x >= 0)
Dependent types allow types to be computed from functions (and depend on arguments, otherwise it seems they become just weird constants), def Five(as_type: String) -> NumericType(as_type):
match as_type:
"string" => "five"
"int" => 5
"float" => 5.0f
"double" => 5.0d
_ => panic() // Unnecessary if you refine `as_type` from a String to an enum or a fixed set of strings.
Dependent types seem weird, but they help making types first-class (https://www.youtube.com/watch?v=mOtKD7ml0NU&t=325s) and gaining types like `Array<T, N>` that allow ensuring things are the right length, and define append/extend properly.I just realized my lambda syntax on the Nat predicate is redundant because I didn't clean up and that using snake_case for function names would be better in a language that lets you operate on functions like they are values.
Like if `(Nat 5) - (Nat 6)`. Or is subtraction disallowed?
let x = Nat 5;
let y = read_nat();
assert y < x; // without this, the following would fail to type check
x - y
(you need occurrence typing, too, in this example)In terms of numbers, what you can expect from refinement types is similar to what you get with CLP(FD) in Prolog.
Maybe some operations can be proved to stay within the refined type, like adding natural numbers, but that's something that the used would need to provide as a function allowing that under assertions or some proof that the compiler can verify and trust.
Refinement types typically(1) refers to a type systems that lets you create a subtype of a type through refining (qualifying) with a predicate or constraint on the shape. Examples {x \in int | is_even x } or { x \in List | len(x) = 1 }
Refinement types can be very powerful but that may well make type checking undecidable (think of a type of Turing machines, and the refinement that keeps only the ones that halt). By being careful about the logic used in the refinements, one may retain decidability.
(1) The article seems to have a different idea of what a refinement type is: quote "a type system that does its work after another type system has already done its work".
I am not going to play orthodox guardian of type theory terminology here, yet to me personally, it does seem unfortunate to use that term. The author seems to really want a form of type-level computation, which could be interesting if it could be rigorously specified and it's relation to the existing type level reduction clarified.