某类的数据成员

时间:2013-04-17 15:56:03

标签: haskell polymorphism

简化问题

鉴于

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.intersectShape.intersect签名的唯一区别在于返回类型。

现在我想添加一个基本上将Shape转换为Primitive的包装器。

我认为它的工作方式大致如下:

data ShapeWrapperPrimitive t = ShapeWrapperPrimitive {
                                  shape :: (Shape s) => s t
                               }

或者换句话说,我想添加一个shape类的Shape成员。

然而,这给了我Illegal polymorphic or qualified type

4 个答案:

答案 0 :(得分:3)

我不确定您的简化问题是否真的是对实际问题的简化。 简化问题的答案是:

如果您对类Foo的实例的未知类型唯一可以做的就是将其转换为Float,那么您也可以存储Float

所以你要用

data Bar = Bar Float

但是,如果我正确理解您的实际问题,那么您希望包装一个类Shape的实例,从而将其转换为类{{1}的实例}}。为此,我要定义

Primitive

然后说

newtype ShapeWrapperPrimitive s t = ShapeWrapperPrimitive (s t)

答案 1 :(得分:2)

这不是您提出的问题的答案,但它可能会有所帮助。如果您要创建包含ShapePrimitive的列表,那么您需要一个包装类型,如thoferon所述。但如果你不是,那么也许你真的不需要包装类型。

您说“注意Primitive.intersectShape.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解决了我的问题。