6

Haskellでジオメトリライブラリをまとめています。リリースするつもりはありません。言語の知識を向上させるために使用しているプロジェクトにすぎません。

Local次の定義を持つデータ型があります

data Local a where
    MkLocal :: (Vectorise a) => ReferenceFrame -> a -> Local a

参照フレームは、フレームの原点を指すベクトルであり、フレームの回転を表す角度であり、どちらも「絶対」参照フレームに対して定義されます (ねえ、それは現実世界ではありません!)。ジオメトリは、のVectoriseリストへの可逆変換を持つものですVector

Local はFunctor次のようなインスタンスになる可能性があることに気づきました。

instance Functor Local where
     fmap f geom = localise (frame geom) (f $ local geom)

しかし、コンパイラは、定義で localize を使用するための Vectorisable のインスタンスがないと文句を言います。無数のGHC拡張機能の1つを使用して、この制限を回避する方法はありますか?

編集:コメントで要求されているように、使用されているタイプの一部を次に示します

local :: Local a -> a
frame :: Local a -> ReferenceFrame
localise :: (Vectorise a) => ReferenceFrame -> a -> Local a

エラーは

No instance for (Vectorise b)
  arising from a use of `localise'
In the expression:
  localise (frame geom) (f $ local geom)
In an equation for `fmap':
    fmap f lgeom = localise (frame geom) (f $ local geom))
In the instance declaration for `Functor Local'

fmapの型が であるため、これは理にかなっています(a -> b) -> f a -> f baのインスタンスである必要があると推測できますが、(どういうわけか) 指定できない限り、別の型クラスを定義せずに制限された戻り値の型を持たなければならないことをコンパイラーに伝えるVectoriseことができるかどうかをどのように推測できるか疑問に思っていました。ほぼすでに法案に適合しています(または、この方法でクラスを制限すると型の推論が何らかの形で壊れる理由を誰かが有益に説明できれば)。bf

ps。私はまた、定義で反転して反転localしたタイプミスを修正しましたframefmap

4

1 に答える 1

13

問題は、localiseその 2 番目の引数が type を持つ必要があることですが、 ( type を持つ) を( typeの) の結果にVectorise a => a適用すると、結果の値が のインスタンスである型を持つという保証はありません。あなたが本当に欲しいのは、制約を持つ型でのみ機能する の類似物です。fa -> blocalVectorise a => aVectoriseFunctorVectorise

最近まで、そのような型クラスを定義することはできませんでした。これはよく知られた問題であり、インスタンスData.Setがない理由です。しかし、最近のGHC拡張により、そのような「制限されたファンクタ」がついに可能になりました:FunctorMonadConstraintKinds

{-# LANGUAGE GADTs, ConstraintKinds, TypeFamilies #-}
module Test
       where

import GHC.Exts (Constraint)

data ReferenceFrame = ReferenceFrame

class Vectorise a where
  ignored :: a

data Local a where
    MkLocal :: ReferenceFrame -> a -> Local a

local :: Vectorise a => Local a -> a
local = undefined

frame :: Local a -> ReferenceFrame
frame = undefined

localise :: (Vectorise a) => ReferenceFrame -> a -> Local a
localise = undefined

class RFunctor f where
  type SubCats f a :: Constraint
  type SubCats f a = ()
  rfmap ::  (SubCats f a, SubCats f b) => (a -> b) -> f a -> f b

instance RFunctor Local where
  type SubCats Local a = Vectorise a
  rfmap f geom = localise (frame geom) (f $ local geom)

詳細については、ConstraintKinds こちらこちらをご覧ください。

于 2013-04-04T12:53:32.060 に答える