2

简化问题

给定

class Foo f where
    frobnicate :: f -> Float

我怎么能允许任何instanceFoo进入

 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.

4

4 回答 4

3

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

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

所以你会使用

data Bar = Bar Float

但是,如果我正确理解了您的实际问题,那么您想要包装一个作为 class 实例的类型Shape,从而将其转换为 class 的实例Primitive。为此,我会定义

newtype ShapeWrapperPrimitive s t = ShapeWrapperPrimitive (s t)

然后说

instance Shape s => Primitive (ShapeWrapperPrimitive s) where
  intersect = ... -- fill in definition here
于 2013-04-17T16:15:30.610 回答
2

这不是您提出的问题的答案,但它可能会有所帮助。如果您要创建一个同时包含Shapes 和Primitives 的列表,那么您需要一个包装器类型,如 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
于 2013-04-17T16:30:05.843 回答
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
  -- ...
于 2013-04-17T16:15:38.927 回答
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)

第一个会添加 ans和 at作为成员,而我真的想要一个s t; 添加括号解决了我的问题。

于 2013-04-17T19:44:01.477 回答