I have the following code:
type Drawable = '["object" ::: Object, "transform" ::: M44 GL.GLfloat]
objXfrm :: "transform" ::: M44 GL.GLfloat
objXfrm = Field
objRec :: "object" ::: Object
objRec = Field
drawObject :: (Drawable `ISubset` a) => M44 GL.GLfloat -> PlainRec a -> IO ()
drawObject camera obj =
withVAO vao $ do
GL.currentProgram $= Just (program shdr)
setUniforms shdr (modelView =: (rGet objXfrm obj !*! camera))
GL.polygonMode $= (GL.Line, GL.Line)
GL.drawElements GL.Triangles inds GL.UnsignedInt nullPtr
where Object {objVAO = vao, objNumIndices = inds, objShader = shdr}
= rGet objRec obj
When I get rid of the type on drawObject
it compiles fine, but with the type I get
Could not deduce (IElem * ("transform" ::: V4 (V4 GL.GLfloat)) a)
arising from a use of `rGet'
from the context (ISubset * Drawable a)
...
Could not deduce (IElem * ("object" ::: Object) a)
arising from a use of `rGet'
from the context (ISubset * Drawable a)
The type that GHC deduces for me is
drawObject
:: (IElem * ("object" ::: Object) rs,
IElem * ("transform" ::: V4 (V4 GL.GLfloat)) rs) =>
V4 (V4 GL.GLfloat)
-> Rec rs Data.Functor.Identity.Identity -> IO ()
And that works fine as a type signature, but the one with ISubset
does not. The error is exactly the same if I interchange the arguments to ISubset
. What is going on here?
Looking at the source code for Vinyl,
IElem x xs
(which is a synonym forImplicit (Elem x xs)
) has two instances:Note that there is no mention of
Subset
here. Logically,(x ∈ xs) ∧ (xs ⊆ ys) ⇒ (x ∈ ys)
, but since there is no instance with the signatureImplicit (Subset xs ys), Implicit (Elem x xs) => Implicit (Elem x ys)
, Haskell has no way of inferring the appropriate instance. Furthermore, no such instance can be written because doing so would result in some nasty instance overlap.As a possible workaround, we can manipulate the membership witnesses (
Elem
andSubset
) directly in order to force the appropriate instances (this is totally untested, and may fail miserably):