Type equality constraints aren't used by solver
gergoerdi opened this issue · 8 comments
The following code fails to typecheck:
{-# LANGUAGE GADTs, ScopedTypeVariables, DataKinds, KindSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE Rank2Types #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-}
import Data.Singletons.Prelude.Num
import Data.Singletons
import GHC.TypeLits
data Foo :: Nat -> * where
FZ :: Foo 0
FS :: Foo n -> Foo (n + 1)
sPred :: (KnownNat n) => Sing (n+1) -> Sing n
sPred _ = sing
foo :: forall a n. (KnownNat n) => a -> (forall m. KnownNat m => Sing m -> a) -> Foo n -> a
foo x0 f = go (sing :: Sing n)
where
go :: forall k. (KnownNat k) => Sing k -> Foo k -> a
go s FZ = x0
go s (FS _) = f (sPred s)
The error message is as follows (on GHC 8.0.2):
KnownNatSolverBug.hs:25:19: error:
* Could not deduce (KnownNat n1) arising from a use of `f'
from the context: KnownNat n
bound by the type signature for:
foo :: KnownNat n =>
a -> (forall (m :: Nat). KnownNat m => Sing m -> a) ->
at KnownNatSolverBug.hs:20:1-91
or from: KnownNat k
bound by the type signature for:
go :: KnownNat k => Sing k -> Foo k -> a
at KnownNatSolverBug.hs:23:5-56
or from: k ~ (n1 + 1)
bound by a pattern with constructor:
FS :: forall (n :: Nat). Foo n -> Foo (n + 1),
in an equation for `go'
at KnownNatSolverBug.hs:25:11-14
Possible fix:
add (KnownNat n1) to the context of the data constructor `FS'
* In the expression: f (sPred s)
In an equation for `go': go s (FS _) = f (sPred s)
In an equation for `foo':
foo x0 f
= go (sing :: Sing n)
where
go :: forall k. (KnownNat k) => Sing k -> Foo k -> a
go s FZ = x0
go s (FS _) = f (sPred s)
To highlight, the relevant parts of the context are:
* Could not deduce (KnownNat n1) arising from a use of `f'
from: KnownNat k
or from: k ~ (n1 + 1)
But isn't this exactly the situation that the plugin was designed to handle?
Actually foo
above can be simplified further to just:
foo :: forall a n. (KnownNat n) => a -> (forall m. KnownNat m => Sing m -> a) -> Sing n -> Foo n -> a
foo x0 f s FZ = x0
foo x0 f s (FS _) = f (sPred s)
KnownNatSolverBug.hs:22:21: error:
* Could not deduce (KnownNat n1) arising from a use of `f'
from the context: KnownNat n
or from: n ~ (n1 + 1)
Thanks for the report, and simple test case. I'll try to look into this over the weekend.
The following example, even simpler, cuts right to the crux of the issue:
{-# LANGUAGE DataKinds, TypeFamilies, TypeOperators #-}
{-# LANGUAGE Rank2Types, FlexibleContexts #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-}
import Data.Singletons
import GHC.TypeLits
bar :: (KnownNat n, n ~ (m+1)) => (forall k. KnownNat k => Sing k -> a) -> Sing m -> a
bar f s = f s
bug.hs:11:11: error:
• Could not deduce (KnownNat m) arising from a use of ‘f’
from the context: (KnownNat n, n ~ (m + 1))
I strongly believe that this is because offset
, in constraintToEvTerm
, doesn't handle the case when classifyPredType ty'
returns an EqPred
instead of a ClassPred
.
Of course, it's tricky if we also want to support chains of equalities like in
bar :: (KnownNat k, k ~ (n+1), n ~ (m+1)) => (forall x. KnownNat x => Sing x -> a) -> Sing m -> a
bar f s = f s
so it seems that from the EqPred
s, we'd need to interpret the semantics of the equalities somehow, it's not just a matter of mere syntactic transformation like rewriting by all equalities.
{-# LANGUAGE DataKinds, TypeOperators, TypeFamilies #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-}
{-# OPTIONS_GHC -dcore-lint #-}
module EqTest where
import GHC.TypeLits
foo :: (KnownNat n, n ~ (m+1)) => proxy m -> Integer
foo m = natVal m
works with the above mentioned patch
Just ran into a similar issue:
{-# LANGUAGE AllowAmbiguousTypes, DataKinds, TypeFamilies, TypeOperators #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-}
{-# OPTIONS_GHC -dcore-lint #-}
module EqTest where
import Numeric.Natural
import GHC.TypeNats
foo :: (KnownNat n, KnownNat m, k ~ (n + m)) => proxy k -> Natural
foo = natVal
This produces the following error:
src/EqTest.hs:12:7: error:
• Could not deduce (KnownNat k) arising from a use of ‘natVal’
from the context: (KnownNat n, KnownNat m, k ~ (n + m))
bound by the type signature for:
foo :: forall (n :: Nat) (m :: Nat) (k :: Nat) (proxy :: Nat -> *).
(KnownNat n, KnownNat m, k ~ (n + m)) =>
proxy k -> Natural
at src/EqTest.hs:11:1-66
Possible fix:
add (KnownNat k) to the context of
the type signature for:
foo :: forall (n :: Nat) (m :: Nat) (k :: Nat) (proxy :: Nat -> *).
(KnownNat n, KnownNat m, k ~ (n + m)) =>
proxy k -> Natural
• In the expression: natVal
In an equation for ‘foo’: foo = natVal
|
12 | foo = natVal
| ^^^^^^
I'm on GHC 8.6.5, and using ghc-typelits-knownnat
and ghc-typelits-natnormalise
version 0.7.