I'm working in an example of dependently typed program in Haskell and I would like to "rewrite" an evidence of propositional equality type a :~: b
defined in singletons library.
More specifically, I have a data type for represent evidence of regular expression membership. My trouble is how to deal with evidence of concatenation of two regular expressions. In my code, I have a GADT called InRegExp xs e
that express the fact that xs
is in the language of regular expression e
. For concatenation, I have the following constructor:
InCat :: InRegExp xs l -> InRegExp ys r ->
(zs :~: xs ++ ys) -> InRegExp zs (Cat l r)
So far, so good. Now I want to define an inversion lemma for membership in concatenation of two regular expressions:
inCatInv :: InRegExp (xs ++ ys) (Cat e e') -> (InRegExp xs e , InRegExp ys e')
inCatInv (InCat p p' Refl) = (p , p')
but the code is rejected by GHC with the following error message:
Could not deduce (xs1 ~ xs)
from the context ('Cat e e' ~ 'Cat l r)
bound by a pattern with constructor
InCat :: forall (zs :: [Nat])
(xs :: [Nat])
(l :: RegExp [Nat])
(ys :: [Nat])
(r :: RegExp [Nat]).
InRegExp xs l
-> InRegExp ys r -> zs :~: (xs ++ ys) -> InRegExp zs ('Cat l r),
in an equation for ‘inCatInv’
at /Users/rodrigo/Dropbox/projects/haskell/experiments/src/Lib.hs:44:11-25
or from ((xs ++ ys) ~ (xs1 ++ ys1))
bound by a pattern with constructor
Refl :: forall (k :: BOX) (b :: k). b :~: b,
in an equation for ‘inCatInv’
at /Users/rodrigo/Dropbox/projects/haskell/experiments/src/Lib.hs:44:22-25
‘xs1’ is a rigid type variable bound by
a pattern with constructor
InCat :: forall (zs :: [Nat])
(xs :: [Nat])
(l :: RegExp [Nat])
(ys :: [Nat])
(r :: RegExp [Nat]).
InRegExp xs l
-> InRegExp ys r -> zs :~: (xs ++ ys) -> InRegExp zs ('Cat l r),
in an equation for ‘inCatInv’
at /Users/rodrigo/Dropbox/projects/haskell/experiments/src/Lib.hs:44:11
‘xs’ is a rigid type variable bound by
the type signature for
inCatInv :: InRegExp (xs ++ ys) ('Cat e e')
-> (InRegExp xs e, InRegExp ys e')
at /Users/rodrigo/Dropbox/projects/haskell/experiments/src/Lib.hs:43:13
Expected type: InRegExp xs e
Actual type: InRegExp xs1 l
Relevant bindings include
p :: InRegExp xs1 l
(bound at /Users/rodrigo/Dropbox/projects/haskell/experiments/src/Lib.hs:44:17)
inCatInv :: InRegExp (xs ++ ys) ('Cat e e')
-> (InRegExp xs e, InRegExp ys e')
(bound at /Users/rodrigo/Dropbox/projects/haskell/experiments/src/Lib.hs:44:1)
In the expression: p
In the expression: (p, p')
In Agda or Idris, this kind of inversion lemma works just fine. Is possible to express such inversion lemma in Haskell? The complete code is available in the following gist.
Any tip or explanation of how can I express such lemma or why it isn't possible to express is highly appreciated.
(xs ++ ys) ~ (xs' ++ ys')
- remember that thexs
andys
inside the constructor are existentially quantified, so they give rise to new type variables - from which the compiler is unable to deduce thatxs ~ xs'
andys ~ ys'
. Instead of using propositional equality, you'll need to have an inductive proof thatxs ++ ys = zs
- I'm guessing thatinCatInv
will have to be recursive as well. – user2407038[] ++ [x]
is indistinguishable from[x] ++ []
, and so the type ofinCatInv
is inherently ambiguous. More precisely, whoever callsinCatInv
gets to choosexs,ys
, with the only constraint thatxs++ys
is the same list as in theInRegExp
type. So, theinCatInv
type is promising to the caller that it can splitzs
into any possible way asxs++ys
(caller's choice), which is not what it really does (nor what it is intended to do, AFAICS). – chiInRegexp ("ab" ++ "c") (Cat "a" "bc")
doesn't implyInRegexp "ab" "a"
. – András Kovácsxs ++ ys = zs
, I'll need to recurse over the structure ofxs
, using a singletonSList xs
, right? Or there's other way to do this? – Rodrigo RibeirounsafeCoerce
which would not required aSList
(just aProxy
). – user2407038