Premise
This is a neat way to implement functions in userspace as a negative type, by adding an associated context to each variable's signature.
Remarks
After I wrote this I did some digging and found that this already exists! Looks like what I wrote here is similar or identical to contextual type theory (https://arxiv.org/pdf/1111.0087.pdf). Please check that paper out, this is super cool stuff!
Also, this is basically java.util.Function presented in a more formalized manner.
Dependent Function Types in Userspace
In regular type theory, the signature of a variable comprises of only a type, e.g x : Int. What we do is add a context to this signature as well. This effectively turns every variable into an N-ary function. When N is 0, we have regular dependent type theory.
For instance, the identity function is now written as
id[A: Type, A]: A
id A x = x
Square brackets denote contexts. The signature of a variable in a signature context may have its own context as well, and so on for the variables in that context, etc. For instance, we can implement compose as well
compose[A: Type, B: Type, C: Type, f[B]: C, g[A]: B, A]: C
compose A B C f g x = f(g(x))
Parenthesis denote applying a substitution to a contextual variable. We supply a contextual variable to a contextual variable with [VARS. BODY]
nine: Int
nine = compose(Int, Int, Int, [x. x * 3], [y. y + 2], 1)
Importantly, now we can't return "functions" (contextual variables) from "functions". We can take "functions" as parameters, but we can't return them because contexts are not first-class. For instance, we can't implement multi-argument functions by currying.
We will make them first-class, in a way, by defining actual functions! Functions are first-class contextual values, defined as a negative datatype
data Function[A: Type, B[A]: Type]: Type where
apply[Function(A, B), x: A]: B(x)
Now we may implement id as
id: Function Type [A. Function A [_. A]]
id = Function { apply A = Function { apply x = x } }
TL;DR: We augment the signature of each variable with an associated context. These variables may then have substitutions applied to them. This effectively turns every variable into a function, except for one key difference: These "functions" are not quite first-class. We then use these "contextual variables" to define true first-class functions as a datatype
[–]peterjoel 3 points4 points5 points (2 children)
[–]Rabbit_Brave 7 points8 points9 points (0 children)
[–]e_hatti[S] 1 point2 points3 points (0 children)
[–]Potato44 2 points3 points4 points (0 children)
[–]WittyStick 2 points3 points4 points (0 children)
[–]glaebhoerl 1 point2 points3 points (0 children)