I'm playing around with the constraints package (for GHC Haskell). I have a type family for determining if a type-level list contains an element:

type family HasElem (x :: k) (xs :: [k]) where HasElem x '[] = False HasElem x (x ': xs) = True HasElem x (y ': xs) = HasElem x xs

This works, but one thing it doesn't give me is the knowledge that

HasElem x xs entails HasElem x (y ': xs)

since the type family isn't an inductive definition of the "is element of" statement (like you would have in agda). I'm pretty sure that, until GADTs are promotable to the type level, there is no way to express list membership with a data type.

So, I've used the constraints package to write this:

containerEntailsLarger :: Proxy x -> Proxy xs -> Proxy b -> (HasElem x xs ~ True) :- (HasElem x (b ': xs) ~ True) containerEntailsLarger _ _ _ = unsafeCoerceConstraint

Spooky, but it works. I can pattern match on the entailment to get what I need. What I'm wondering is if it can ever cause a program to crash. It seems like it couldn't, since unsafeCoerceConstraint is defined as:

unsafeCoerceConstraint = unsafeCoerce refl

And in GHC, the type level is elided at runtime. I thought I'd check though, just to make sure that doing this is ok.

--- EDIT ---

Since no one has given an explanation yet, I thought I would expand the question a little. In the unsafe entailment I'm creating, I only expect a type family. If I did something that involved typeclass dictionaries instead like this:

badEntailment :: Proxy a -> (Show a) :- (Ord a) badEntailment _ = unsafeCoerceConstraint

I assume that this would almost certainly be capable of causing a segfault. Is this true? and if so, what makes it different from the original?

--- EDIT 2 ---

I just wanted to provide a little background for why I am interested in this. One of my interests is making a usable encoding of relational algebra in Haskell. I think that no matter how you define functions to work on type-level lists, there will be obvious things that aren't proved correctly. For example, a constraint (for semijoin) that I've had before looked like this (this is from memory, so it might not be exact):

semijoin :: ( GetOverlap as bs ~ Overlap inAs inBoth inBs , HasElem x as, HasElem x (inAs ++ inBoth ++ inBs)) => ...