我正在将一个几何库放在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实例进行localize。有没有办法解决这个限制使用无数的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) -> f a -> f b
。它可以推断出a
必须是Vectorise
的一个实例,但我想知道它是如何推断b
的,除非我能指定(不知何故)我可以告诉编译器{ {1}}必须具有受限制的返回类型,而没有定义另一个类型类,当已经有一个几乎已经适合该帐单时(或者,如果有人可以帮助解释为什么以这种方式限制类会破坏类型)推论某种方式)。
PS。我还修正了一个拼写错误,我在f
local
和frame
答案 0 :(得分:13)
问题在于localise
要求其第二个参数具有类型Vectorise a => a
,但是当您将f
(类型为a -> b
)应用于{{local
时1}}(类型为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)