鉴于
class Foo f where
frobnicate :: f -> Float
我怎么能在
中允许任何instance
Foo
data Bar = Bar { <here> }
鉴于
-- Typically lightweight geometric objects, e.g. spheres
class Shape s where
intersect :: (RealFrac t, Floating t, Ord t, Shape s)
=> Ray t -> s t -> Maybe (DifferentialGeometry t)
和
-- Primitives contain higher level informations, like material properties
class Primitive p where
intersect :: (RealFrac t, Floating t, Ord t, Primitive p)
=> Ray t -> p t -> Maybe (Intersection t)
请注意Primitive.intersect
和Shape.intersect
签名的唯一区别在于返回类型。
现在我想添加一个基本上将Shape
转换为Primitive
的包装器。
我认为它的工作方式大致如下:
data ShapeWrapperPrimitive t = ShapeWrapperPrimitive {
shape :: (Shape s) => s t
}
或者换句话说,我想添加一个shape
类的Shape
成员。
然而,这给了我Illegal polymorphic or qualified type
。
答案 0 :(得分:3)
我不确定您的简化问题是否真的是对实际问题的简化。 简化问题的答案是:
如果您对类Foo
的实例的未知类型唯一可以做的就是将其转换为Float
,那么您也可以存储Float
所以你要用
data Bar = Bar Float
但是,如果我正确理解您的实际问题,那么您希望包装一个类Shape
的实例,从而将其转换为类{{1}的实例}}。为此,我要定义
Primitive
然后说
newtype ShapeWrapperPrimitive s t = ShapeWrapperPrimitive (s t)
答案 1 :(得分:2)
这不是您提出的问题的答案,但它可能会有所帮助。如果您要创建包含Shape
和Primitive
的列表,那么您需要一个包装类型,如thoferon所述。但如果你不是,那么也许你真的不需要包装类型。
您说“注意Primitive.intersect
和Shape.intersect
签名的唯一区别在于返回类型。”您可以使用类型族表示该关系,如下所示。这为您提供了一个名为Thing
的类型系列。对于作为intersect
实例的每种类型,Thing
的结果类型可能不同。
{-# LANGUAGE TypeFamilies, TypeSynonymInstances #-}
class Thing t where
type Result t
intersect :: Ray t -> s t -> Maybe (Result t)
-- Made-up type definitions just to get things to compile
data Shape s t = Shape s t
data Primitive p t = Primitive p t
type Ray t = (Double, t)
type DifferentialGeometry t = [t]
type Intersection t = [t]
-- Typically lightweight geometric objects, e.g. spheres
instance Thing (Shape s t) where
type Result (Shape s t) = DifferentialGeometry t
intersect a b = undefined
-- Primitives contain higher level informations, like material properties
instance Thing (Primitive p t) where
type Result (Primitive p t) = Intersection t
intersect a b = undefined
答案 2 :(得分:1)
我可以看到解决这类问题的两种方法:
1)使用语言扩展名ExistentialQuantification
。所以你可以写:
data Blah = forall a. Num a => Blah a
2)将约束移动到您的函数,如
data Blah a = Blah a
f :: (Num a) => Blah a -> a
f = undefined
或您的实例:
instance (Num a) => Foo (Blah a) where
-- ...
答案 3 :(得分:0)
即使我接受了另一个答案,我也会将此发布给未来的访问者。
我的问题或多或少是一个可能被认为是错字的问题。在某些时候,我有
23: data ShapeWrapperPrimitive s t = ShapeWrapperPrimitive s t
24:
25: instance (Shape s) => Primitive (ShapeWrapperPrimitive s) where
26: intersect _ _ = Nothing
--- >> line 25: Expecting one more argument to `s'
让我走上困惑和折磨的道路。注意它是如何指向第25行的。接受的答案揭示了我的错误:而不是
data ShapeWrapperPrimitive s t = ShapeWrapperPrimitive s t
我需要
data ShapeWrapperPrimitive s t = ShapeWrapperPrimitive (s t)
第一个会添加一个s
和一个t
作为成员,而我真的想要一个s t
;添加parens解决了我的问题。