类型和GADT

时间:2013-04-04 10:58:05

标签: haskell

我正在将一个几何库放在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

的定义中颠倒了localframe

1 个答案:

答案 0 :(得分:13)

问题在于localise要求其第二个参数具有类型Vectorise a => a,但是当您将f(类型为a -> b)应用于{{local时1}}(类型为Vectorise a => a),不能保证结果值的类型是Vectorise的实例。您真正想要的是Functor的模拟,它仅适用于具有Vectorise约束的类型。

直到最近,才能定义这样的类型类。这是一个众所周知的问题以及Data.Set没有FunctorMonad实例的原因。然而,随着最近的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 herehere