类型类和GADT
我在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)
但是编译器抱怨在定义中没有Vectorisable的实例用于本地化。 使用无数的GHC扩展之一有没有办法解决这个限制?
编辑:根据评论的要求,这里是一些使用的类型
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) -> fa -> fb
。 它可以推断出a
必须是Vectorise
一个实例,但我想知道它是如何推断b
,除非我可以指定(以某种方式)我可以告诉编译器f
必须有限制的返回类型,而不需要定义另一个typeclass已经是一种几乎符合法案的条款(或者,如果有人能够有助于解释为什么以这种方式限制类别会以某种方式破坏类型推断)。
PS。 我还修复了一个错误,我在fmap
的定义中颠倒了local
和frame
问题是localise
需要它的第二个参数具有类型Vectorise a => a
,但是当您将f
(它具有类型a -> b
)应用于local
(类型Vectorise a => a
)的结果时,没有保证结果值的类型是Vectorise
一个实例。 你真正想要的是一个Functor
的模拟,它只适用于具有Vectorise
约束的类型。
直到最近,还不可能定义这样的类型类。 这是一个众所周知的问题,也是Data.Set
没有Functor
或Monad
实例的原因。 然而,随着最近ConstraintKinds
GHC的扩展,这些“受限函子”终于成为可能:
{-# 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
信息。