我想创建一个类型类GetGLInfo
,它包含多个OpenGL
函数所需的一些基本类型信息:
class GetGLInfo v where
numComponents :: v -> GL.GLint
bytesPerComponent :: v -> Int
openGLType :: v -> GL.GLenum
简单的实例是Float
:
instance GetGLInfo Float where
numComponents _ = 1
bytesPerComponent = sizeOf
openGLType _ = GL.GL_FLOAT
我想使用构造函数data a :. b
为Data.Vec矢量数据类型创建此类的实例:
import qualified Data.Vec as Vec
instance GetGLInfo a => GetGLInfo ((Vec.:.) a ()) where
numComponents _ = 1
bytesPerComponent = (bytesPerComponent).(Vec.head)
openGLType = (openGLType).(Vec.head)
instance (GetGLInfo a, GetGLInfo b) => GetGLInfo ((Vec.:.) a b) where
numComponents (_ Vec.:. r)= 1 + (numComponents r)
bytesPerComponent = (bytesPerComponent).(Vec.head)
openGLType = (openGLType).(Vec.head)
我会使用numComponents = Vec.length
但我有更多的类型错误......
为openGLType
致电Vec2
时,我收到以下错误:
let c = openGLType ((0.0 :. 1.0 :. ()) :: Vec2 Float)
error:
* Overlapping instances for GetGLInfo (Float :. ())
arising from a use of `openGLType'
Matching instances:
instance GetGLInfo a => GetGLInfo (a :. ())
-- Defined in `GLTypeInfo'
instance (GetGLInfo a, GetGLInfo b) => GetGLInfo (a :. b)
-- Defined in `GLTypeInfo'
* In the expression: openGLType ((0.0 :. 1.0 :. ()) :: Vec2 Float)
In an equation for `c':
c = openGLType ((0.0 :. 1.0 :. ()) :: Vec2 Float)
为什么我的实例在这里重叠?
是否有一种简单的方法可以创建(:.) a b
的实例而没有基本案例(:.) a ()
的显式实例?
答案 0 :(得分:1)
您必须使归纳实例与基本案例实际区分开来。现在,((Vec.:.) a ())
仅仅是((Vec.:.) a b)
的一个特例,这就是“重叠实例”的含义。但是如果b
本身已经是非零维的话,你希望后者只匹配。好吧,明确说明:
instance (GetGLInfo a, GetGLInfo b, GetGLInfo xs) => GetGLInfo (a:.b:.xs) where
numComponents (_:.b:.xs)= 1 + numComponents (b:.xs)
bytesPerComponent = bytesPerComponent . Vec.head
openGLType = openGLType . Vec.head
另外,原则上更优雅的是Alexey Romanov所建议的:使基本情况为零维度。但显然没有GL_VOID
,所以这里没有选择。
作为一种完全不同的方法,我建议只为标量创建自己的类,然后在任意向量空间上进行推广:
import Data.VectorSpace
import Data.Basis
class GLScalar s where
scalar_bytesPerComponent :: Functor proxy => proxy s -> Int
scalar_openGLType :: Functor proxy => proxy s -> GL.GLenum
instance GLScalar Float
bytesPerComponent :: ∀ v proxy
. (VectorSpace v, GLScalar (Scalar v), Functor proxy)
=> proxy v -> Int
bytesPerComponent _ = scalar_bytesPerComponent ([]::[Scalar v])
numComponents :: ∀ v . HasBasis v => v -> Int
numComponents = length . decompose