aya-prover / aya-dev

A proof assistant and a dependently-typed language
https://www.aya-prover.org
MIT License
278 stars 16 forks source link

Coercion #50

Open re-xyr opened 3 years ago

re-xyr commented 3 years ago

As title

re-xyr commented 3 years ago

random thoughts:

tonyxty commented 3 years ago
  • I believe that coercion is just custom subtyping rules. Am I right?

We might need a more precise definition of "subtyping." For now, I would define coercion as "functions that are implicitly inserted during elabration to make things tyck."

  • I don't like Arend's syntax of putting corecion into a \where block. I prefer writing coercion rules as a global definition.

Arend is totally abusing \where blocks! On the other hand, coercion rules might also need some form of scope control.

ice1000 commented 3 years ago

We might need a more precise definition of "subtyping." For now, I would define coercion as "functions that are implicitly inserted during elabration to make things tyck."

Totally agreed

On the other hand, coercion rules might also need some form of scope control.

Yes. I suggest 'this coercion is accessible by name directly' = 'this coercion is in scope'

ice1000 commented 3 years ago

Does Arend coercion allow coercing a type with parameters, like \all {A} {n : Nat} -> Vec A n -> List A?

I don't know. I wish we could have that :worried:

re-xyr commented 3 years ago

Does Arend coercion allow coercing a type with parameters, like \all {A} {n : Nat} -> Vec A n -> List A?

I don't know. I wish we could have that 😟

I think this look interesting and I do not know if any language has this. Arend seems not. Maybe it is somehow novel (in an implementation sense) and can be very powerful.

re-xyr commented 3 years ago

We have a paper on coercion for HM here: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/icfp051-swamy.pdf

Maybe we can base our DT coercion on it.

re-xyr commented 3 years ago

One problem to handle is ambiguous coercions. Say one write A -> B and B -> C and A -> C coercions. We will be unable to know which to use when user passes an A to a position of C. A more subtle case is when we have both coercions (x : B) -> A x -> C and A n -> C where n : B constant and we want to coerce a A n to C.

I cannot think of a way better than giving a an error and ask user to resolve the ambiguity manually.

tonyxty commented 3 years ago

This is totally fine, and that's the reason why we have named coercions, similar to the situation for typeclasses.

re-xyr commented 3 years ago

Maybe we can make coercion a special case of typeclass.

tonyxty commented 3 years ago

Like rust's Into<U>?

ice1000 commented 3 years ago

Like rust's Into<U>?

Yes, and we builtin this thingy.

tonyxty commented 3 years ago

And why we need named coercion instances: https://github.com/coq/coq/issues/9275 So another reason for making coercion typeclasses again.

tonyxty commented 3 years ago

Proposal: don't auto-insert coerce and leave everything to the library. Rationale:

  1. Then coercion is totally a library-level thing. So one less language feature (which seems ad-hoc anyway)
  2. Implicit type-cast might not be a good idea in a language where types play a central role.

The only cost is having to write coerce every time we need it. We can make this name shorter (e.g., _⬇), and the library author can always decide to use {A : Type} {AtoG : Into Group A} (G : A) instead of (G : Group) when that makes more sense. Rust is using this, and in many libraries you can find signatures like fn send<T> (text: T) where T: Into<String>

re-xyr commented 3 years ago

This way we make our language a bit less like a dynamic one. Not sure if this is good or bad though.

Also we can use the sharp symbol or flat symbol to make our code look more musical

re-xyr commented 3 years ago

Of course we can first leave the auto coercion insertion unimplemented and decide later... and maybe we can make it optional (by some kind of pragma) in the future.

tonyxty commented 3 years ago

This way we make our language a bit less like a dynamic one.

Making it look like a dynamic one is not part of our design goal if I recall correctly.

Also we can use the sharp symbol or flat symbol to make our code look more musical

Yes, I think the flat symbol is a reasonable choice.

imkiva commented 3 years ago

Making it look like a dynamic one is not part of our design goal if I recall correctly.

Yeah, explicit is better than implicit.

re-xyr commented 3 years ago

Here is another problem: Should we also make record subtyping explicit? E.g, we have g : Group A and \record Group (A : \Type) \extends Monoid A, should we have g : Monoid A or coerce g : Monoid A?

tonyxty commented 3 years ago

Making it look like a dynamic one is not part of our design goal if I recall correctly.

Yeah, explicit is better than implicit.

But you linked to "Notation Lives Matter" lol

tonyxty commented 3 years ago

Agda is not able to infer this.

And I think we might need some innovation to solve inference problems for such instances.

re-xyr commented 3 years ago

Can Lean4 infer that?

tonyxty commented 3 years ago

Agda is not able to infer this.

Apologies, I think I might have misunderstood Agda's instance mechanism, and I need some time to revise the code. Please ignore my previous comment for now.

tonyxty commented 3 years ago

Ok, turns out it's the problem with what Agda calls "overlapping instances." If you add OPTIONS --overlapping-instances then the code, well, still doesn't compile and Agda enters an infinite loop.

Upon reading Agda's instance resolution algorithm I think they did something wrong: by using a simple DFS, the resolution process gets trapped in trying to insert more and more intermediate steps (From S T -> From S U, From U T -> From S U, From U V, From V T -> etc.

What we need is a BFS, but that's going to consume too much memory. So maybe we should adopt IDDFS, which is going to guarantee a shortest instance resolution depth.

But again, it's still too early to decide on anything.

ice1000 commented 3 years ago

Yes, that sounds like some important decisions, but probably would be done after we make structures available

re-xyr commented 3 years ago

This paper on Lean 4 typeclass resolution seems to claim that it solves this infinite expansion problem.

tonyxty commented 3 years ago

What we need is a BFS, but that's going to consume too much memory. So maybe we should adopt IDDFS, which is going to guarantee a shortest instance resolution depth.

My guess was right, Agda provides an --instance-search-depth option, and after tuning that to 3 the code actually compiled. But Agda should still use IDDFS for instance resolution.

ice1000 commented 3 years ago

I'm thinking 'bout this now. We should implement this to make Aya more 'practical'.