Haskell 某个类的数据成员 简化问题

Haskell 某个类的数据成员 简化问题,haskell,polymorphism,Haskell,Polymorphism,给定 我如何允许Foo的任何实例 data Bar = Bar { <here> } 及 请注意,Primitive.intersect和Shape.intersect的签名的唯一区别在于返回类型 现在我想添加一个包装器,它基本上将任何形状转换为原语 我认为它的工作原理大致如下: data ShapeWrapperPrimitive t = ShapeWrapperPrimitive { shape :: (Sh

给定

我如何允许
Foo
的任何
实例

 data Bar = Bar { <here> }

请注意,
Primitive.intersect
Shape.intersect
的签名的唯一区别在于返回类型

现在我想添加一个包装器,它基本上将任何
形状
转换为
原语

我认为它的工作原理大致如下:

data ShapeWrapperPrimitive t = ShapeWrapperPrimitive {
                                  shape :: (Shape s) => s t
                               }
或者换句话说,我想添加一个任意的
shape
成员,它属于
shape


然而,这给了我非法的多态或限定类型,我不确定你的简化问题是否真的是实际问题的简化。简化问题的答案是:

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

所以你会用

data Bar = Bar Float
但是,如果我正确理解了您的实际问题,那么您希望包装一个类型,该类型是类
形状
的实例,从而将其转换为类
基元
的实例。为此,我将定义

newtype ShapeWrapperPrimitive s t = ShapeWrapperPrimitive (s t)
然后说

instance Shape s => Primitive (ShapeWrapperPrimitive s) where
  intersect = ... -- fill in definition here

我可以看到这类问题的两种解决方案:

1) 使用语言扩展名
。所以你可以写:

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
  -- ...

这不是对你所问问题的回答,但可能会有所帮助。如果要创建一个同时包含
Shape
s和
Primitive
s的列表,则需要一个包装器类型,如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
即使我接受了另一个答案,我还是会把它贴在未来的访问者面前


我的问题或多或少是一个可以被认为是打字错误的问题。在某个时候,我

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
作为成员,而我真的想要一个
st
;添加参数解决了我的问题。

为什么不
数据ShapeWrapperPrimitive s t=…
实例(ShapeS)=>Primitive(ShapeWrapperPrimitive s)在哪里…
呢?@C.A.McCann:哦,你刚才写了
…)看看我自己的答案。我真的习惯了糟糕的错误消息(C++),但Haskell为它添加了一个新维度。人们会习惯吗?GHC的错误信息往往简明扼要,但信息丰富,一旦你学会解读它们的意思(请注意,它所建议的“解决方案”往往是荒谬的)。是的,我想这就是“适应它”。接受,因为即使
newtype
不适用(我想向
ShapeWrapperPrimitive
添加更多数据),也正是您的语法无错误揭示了我的错误:)
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'
data ShapeWrapperPrimitive s t = ShapeWrapperPrimitive s t
data ShapeWrapperPrimitive s t = ShapeWrapperPrimitive (s t)