Closed puffnfresh closed 2 months ago
You can see lots of this live in the optics library, for example:
src.util.get0MapOf :
(Get0Of m {Ix is, Err js, e} a b
->{g,
Coindexed (Get0Of m),
Prism (Get0Of m),
Prism1 (Get0Of m),
Lens (Get0Of m),
MLens0 (Get0Of m),
Indexed (Get0Of m),
MLens (Get0Of m),
Getter (Get0Of m),
MLens1 (Get0Of m),
Getter0 (Get0Of m),
Lens0 (Get0Of m)} Get0Of m {Ix (), Err Void, e} s t)
-> (a ->{e, Err js, Ix is} Optional m)
-> s
->{e, g} Optional m
src.util.get0MapOf op ar s =
(Get0Of sr) = Get0Of.handles op (Get0Of ar)
(do sr s) |> errToEither |> ixProvide!() |> Either.fold absurd id
type src.carriers.Get0Of r e a b = Get0Of (a ->{e} Optional r)
ability src.abilities.Coindexed p where
_withErr :
p {Err js, e} a (Either j b)
->{src.abilities.Coindexed p} p {Err (Either j js), e} a b
_absorbErr :
p {Err (Either j js), e} a b
->{src.abilities.Coindexed p} p {Err js, e} a (Either j b)
You don't need an ability declaration - probably unsurprising since abilities are basically data declarations:
type Exceptional f = Exceptional (f {Exception})
type NaturalAbility e = NaturalAbility (() -> {e} Nat)
oneNaturalAbility : NaturalAbility {Exception}
oneNaturalAbility =
NaturalAbility (_ -> 1)
-- badNat : Exceptional NaturalAbility
badNat =
Exceptional oneNaturalAbility
What's interesting about the above is that it compiles!
⍟ These new definitions are ok to `add`:
type Exceptional f
type NaturalAbility e
badNat : Exceptional NaturalAbility
oneNaturalAbility : NaturalAbility {Exception}
But if you try to copy/paste that type into the file:
Kind mismatch arising from
9 | badNat : Exceptional NaturalAbility
Exceptional expects an argument of kind: Type -> Type; however, it is applied to NaturalAbility
which has kind: Ability -> Type.
Agree this seems wrong, thanks for detailed report! Basically it looks like kind checker won’t infer a type parameter of kind Ability -> Type for some reason. Even when the type param is only applied to things of kind Ability within the type.
@tstat what do you think?
@pchiusano my theory is actually that it's the type application syntax which is generating a bad constraint. It seems like Unison can and does infer the right kind. It just breaks if I write it out.
Yeah, confirmed. I commented out kindCheckAnnotations
and the example above "works"
More minimal example, using the ByteArray builtin (a special case in the constraint generation):
type IOF f = IOF (f {IO})
array : '{IO} IOF mutable.ByteArray
array _ =
n = IO.byteArray 10
IOF n
Something else interesting. This compiles:
type IOF f = IOF (f {IO})
type G = G (IOF mutable.ByteArray)
array : IOF mutable.ByteArray -> Nat
array _ = 0
But this does not:
type IOF f = IOF (f {IO})
array : IOF mutable.ByteArray -> Nat
array _ = 0
This final example is a result of kind defaulting. Looks like the inferred kind for f
in IOF f
is _ -> Type
, which is incorrect. Kind defaulting takes these unconstrained vars and defaults them to Type
, resulting in the erroneous Type -> Type
constraint.
So, this looks like a constraint generation failure where {IO}
isn't constrained to be of kind Ability
? Yeah, if you swap {IO}
for IO
then it does infer the kind Ability -> Type
for f
.
Describe and demonstrate the bug
Input:
Output:
Screenshots
Environment (please complete the following information):
I have tried versions from 4af93e9 (Jan 2024) all the way to e388786 (Aug 2024).
Additional context
In the error, the claim that
NaturalAbility
has kindAbility -> Type
is true. It's wrong thatExceptional
should expect an argument of kindType -> Type
. It seems like something is off with kind inference there.