Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

An idea for abstract function interfaces #178

Open
jonsterling opened this issue Aug 25, 2020 · 2 comments
Open

An idea for abstract function interfaces #178

jonsterling opened this issue Aug 25, 2020 · 2 comments

Comments

@jonsterling
Copy link
Collaborator

jonsterling commented Aug 25, 2020

Functions out of inductive types are defined by eliminators, but this has unfortunate effects: if we unfold the function, then we get the whole brutal eliminator expression, and it is not at all easy to put this 🧞 back in the bottle. In the past I have considered techniques where we have special forms to declare a top-level function, Agda-style --- local functions are still easily accommodated in that setting --- but I have another idea that might be worth considering.

We could decouple the function's interface from its substantiation. The idea is that the interface of an addition function would be as follows:

interface add : nat -> nat -> nat where
| add ze n ----> n
| add (su m) n ----> su (add m n)

Now, this function does not yet exist! In particular, we cannot call add. It has to be implemented first. We implement it using the eliminator:

implementation add :=
  elim [
  | zero => n => n
  | suc {_ => ih} => n => suc {ih n}
  ]

The elaborator checks that add satisfies the interface up to judgmental equality. If that succeeds, we now have an new variable add in scope that does not unfold to anything, but the rewrite rules from the interface have been registered to it! First-order unification, with some tweaks to allow systems to bubble out, is enough to implement the evaluator for such functions.

One day one could try adding tactics that find an implementaiton satisfying those equations --- this is essentially what pattern compilation does, and is worked out by McBride and friends (implemented in Lean nowadays too). It's quite tricky though, so it would be nice to have a middle ground for now.


Subtleties

We must restrict attention to linear patterns.

How to deal with an interface like | omega n ------> omega n? I do not like the idea of trying to have some low ch'i termination checker on the interfaces, since the purpose of the implementation is to provide a termination proof!

My simple answer is that it is unnecessary to register the rewrites until after the termination proof is
substantiated. Checking that the rewrites are modeled by the implementation does not require registering them, so omega n ---> omega n does not pose a problem.

@RobertHarper
Copy link

RobertHarper commented Aug 25, 2020 via email

@jonsterling
Copy link
Collaborator Author

@RobertHarper That's a nice connection with the datatype interfaces, indeed!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants