-
Notifications
You must be signed in to change notification settings - Fork 380
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
Linear functions lose their linearity annotation when wrapped in a monad #758
Comments
I'm guessing inference kicks coercion into action, since fail ma x = (>>=) {a = (1 _ : a) -> b} ma \f => pure (f x) |
One reason why inference does that might be because we don't have multiplicity polymorphism. So when we guess a type for |
In general, fail ma x = MondFun.do (f : (1 _ : a) -> b) <- ma
pure (f x) (As a general principle, any binder should allow type-ascription, but I appreciate this is fiddly to implement.) |
This is not an artefact of |
See #670 |
It's harder to avoid in |
The thing is we should not need to explicitly set the argument, this is a bug with how type inference handles linear types, linking back to general weirdness with linearity subtyping (see #73) |
This, along with a few other things, is making me think we should not have the multiplicity subtyping during unification, because it's really just guessing anyway. On the one hand, it would be a pity to remove it because it's very convenient in a lot of places, but on the other hand, it seems clear it's not the right way to do things. I think I've almost always regretted it eventually when I've tried to introduce some form of subtyping. Removing subtyping at least won't affect my own main use for linearity, which is in resource tracking, but it will mean that some of the things we've been playing with on using linearity for performance will be less useful (e.g. using multiplicity annotations as a hint to a memory allocator) because setting the linearity of an argument will then restrict where a function can be used. I suppose we'll have to find another way to achieve that - multiplicity polymorphism is something we should explore anyway. QTT is a new thing, so we're still exploring how best to use it. But we should still make sure that type checking is sound while we're exploring the new possibilities. |
These days we get: Error: While processing right hand side of fail. There are 0 uses of linear name (implicit) _.
Issue758.idr:14:25--14:35
10 | mb
11 |
12 | fail : LMonad m => (1 _ : m ((1 _ : a) -> b)) -> (1 _ : a) -> m b
13 | fail ma a = Issue758.do f <- ma
14 | ?what_is_f
^^^^^^^^^^ Which suggests to me that do f <- ma
?what_is_f
pure (f a) gets desugared to
but ideally we'd want (and it does indeed work)
where we have cunningly defined: (>>) : LMonad m => (1 _ : m ()) -> (1 _ : m a) -> m a
ma >> mb = ma >>= \ () => mb It should not be too much work to change the way we desugar these do blocks to give |
The fix itself was very easy. The refactoring tied to the choice to make |
Steps to Reproduce
Expected Behavior
Typechecks.
Observed Behavior
Does not typecheck. It fails with error
If we ask the type for hole
what_is_f
we getWhich indicates that
f
has lost its linearity annotation.However, if we wrap each linear function in its own constructor everything works as expected
Here,
what_is_f
reportsf
having type(1 _ : a) -> b
correctlyThe text was updated successfully, but these errors were encountered: