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ここで、基本的に anyをに変換するラッパーを追加したいと思います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 とs の両方を含むリストを作成する場合は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
于 2013-04-17T16:30:05.843 に答える
1

この種の問題には 2 つの解決策があります。

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)

s最初はメンバーとして anと aを追加していたでしょうが、私は本当に;tが欲しかったのです。s t括弧を追加すると問題が解決しました。

于 2013-04-17T19:44:01.477 に答える