假设我们有以下代码:
class C t where
g :: t
instance C Int where
g = 42
很简单。我们还可以在Int上定义函数,如下所示:
f1 :: Int -> Int
f1 x = x * x
我一直在使用类型家族,特别是因为Data.Has
使用它们,我想将它们插入到IxSet
中。
但在这里,我要给出一个简化的例子。假设我们想要定义一个新类型的X
,它类似于Int。我们可以这样做:
type family X
type instance X = Int
然后,我们可以像这样在X
上定义函数:
f2 :: X -> X
f2 x = x * x + 1
到目前为止没有问题。现在让我们尝试定义一个实例C X
,就像我们对C Int
所做的那样
instance C X where
g = 43
哦,现在我们有了以下错误:
非法类型同义词族应用实例:
X
在'C X'
的实例声明中
现在让我们尝试一些不同的东西:
newtype NewX = NewX X
instance C NewX where
g = 43
现在我们有了另一个错误,即:
没有用于
(Num NewX)
的实例
产生于文字'43'
newtype
关键字似乎也消除了关于前一个类属于哪些类的任何信息。然而,我似乎也无法避免newtype
,因为我不能在实例定义中使用类型族。
是否有更好的方法来做到这一点,而不必重写实例定义与额外的显式实例提及,否则将被推断?
背景信息:
我需要这样做的原因如下:
import Data.Has
import Data.IxSet
data Col1 = Col1; type instance TypeOf Col1 = Text
data Col2 = Col2; type instance TypeOf Col2 = Text
type Row = FieldOf Col1 :&: FieldOf Col2;
instance Indexable Row where
empty = ixSet [ixFun $ (\x -> [ Col1 ^. x ]) ] -- Maybe add some more indexes later
但以下几个方面都失败了:
非法类型同义词族应用实例:
Row
在'Indexable Row'
的实例声明中
使Row
成为newtype
会导致以下错误:
(包含(标签为Col1文本)行)的实例没有因使用“^.”而产生。可能的修复:为(包含(标签为Col1文本)行)添加实例声明
解决这个问题的唯一方法是添加一个长派生子句,如下所示:
newtype Row = Row (FieldOf Col1 :&: FieldOf Col2)
deriving
(
Contains (Labelled Col1 Text), -- Add this for every column
Contains (Labelled Col2 Text) -- ...
)
即使是一些允许我"typedef“Contains (Labelled x (TypeOf x))
来说HasCol x
的东西也是有帮助的。
发布于 2012-05-07 19:37:57
newtype
就是这样做的--它定义了一个新类型,而type
定义了一个同义词。如果您不喜欢一堆派生子句,则始终可以使用与底层类型的同构。
instance C NewX where
g = NewX 43
类型同义词不能很好地处理实例声明的原因是函数(包括类型函数)只能朝一个方向工作。您只能在构造函数上匹配模式,因此newtype
允许您以零运行时成本引入一个新的类型构造函数。在你的问题上,为什么不
newtype Row = Row {runRow :: FieldOf Col1 :&: FieldOf Col2}
instance Indexable Row where
empty = ixSet [ixFun $ (\x -> [ Col1 ^. (runRow x) ]) ]
我应该指出,一般来说,GeneralizedNewtypeDeriving
是不健全的。并不意味着你应该避免使用它,但暗示你想要的可能是不可能的。
编辑(提问者):
更好的是,甚至不需要更改数据类型行
newtype Row = Row ( FieldOf Col1 :&: FieldOf Col2 )
instance Indexable Row where
empty = ixSet [ixFun $ (\(Row x) -> [ Col1 ^. x ]) ]
发布于 2012-05-07 18:06:28
下面的文件在这里编译:
{-# LANGUAGE GeneralizedNewtypeDeriving, TypeFamilies #-}
class C a where g :: a
type family X
type instance X = Int
newtype NewX = NewX X deriving Num
instance C NewX where g = 43
https://stackoverflow.com/questions/10491521
复制