How can I tell GHC to satisfy a type-level <= constraint if I know it's true at runtime?
After poking around a bit more, I found Justin L's answer to a similar question. He wrapped up his solution into the typelits-witnesses
package which I was able to use to solve this problem pretty cleanly:
someMyTypeVal :: Integer -> Maybe SomeMyType
someMyTypeVal n = someNatVal n >>= check
where check :: SomeNat -> Maybe SomeMyType
check (SomeNat (_ :: p n)) = case (SNat @1) %<=? (SNat @n) of
LE Refl -> Just (SomeMyType (MyType @n))
NLE _ _ -> Nothing
a %<=? b
lets us compare two type-level natural numbers and gives us a witness for whether a
is less than b
(LE
) or not (NLE
). This gives us the extra constraint in the LE
case to return a SomeMyType
, but trying to do that in the NLE
case would still give us the "can't match ‘1 <=? n’ with ‘'True’" error.
Note the explicit type signature for check
—without it, the type of check
is inferred as check :: SomeNat -> Maybe a
and I would get the following type error:
• Couldn't match type ‘a’ with ‘SomeMyType’
‘a’ is untouchable
inside the constraints: 'True ~ (1 <=? n)
With the explicit type signature everything works and the code is even (reasonably) readable.