在Haskell数据类型中键入类

时间:2022-06-01 17:44:12

In Haskell, one can define a data type like so:

在Haskell中,可以像这样定义数据类型:

data Point1 = Point1 {
    x :: Integer
  , y :: Integer
}

Can one use type classes for variables inside a data type? If so how? I realize it is possible to do this as an algebraic data type, with a different definition for each kind of point, but I'm wondering if there's a way to accomplish this in a more compact and flexible manner.

可以在数据类型中为变量使用类型类吗?如果是这样的话?我意识到有可能将它作为代数数据类型,对每种点都有不同的定义,但我想知道是否有办法以更紧凑和灵活的方式实现这一点。

e.g. Something along the lines of this pseudocode which uses function declaration syntax:

例如这个伪代码使用函数声明语法:

data Point2 = Point2 {
    x :: (Num a, Ord a) => a
  , y :: (Num a, Ord a) => a
}

The goal would be to allow one to store Int, Integer, Float or Double values in the data type. Ideally, I'd like to restrict it so that x and y must be of the same type.

目标是允许在数据类型中存储Int,Integer,Float或Double值。理想情况下,我想限制它,以便x和y必须是相同的类型。

2 个解决方案

#1


You need to decide if you want an existential or universal quantification on that type. Universal quantification, ala:

您需要决定是否要对该类型进行存在性或通用量化。通用量化,ala:

data (Num a, Ord a) => Point2 a = Point2 a a

yields a proof obligation that Num and Ord instances exist for the type 'a' but doesn't actually help all that much, because all it does is give you an obligation when you go to use the Point class by constructing a value of that type or when you go to pattern match it.

产生了一个证明义务,Num和Ord实例存在于类型'a'但实际上并没有那么多帮助,因为当你通过构造该类型的值来使用Point类时,它所做的就是给你一个义务或者当你去模式匹配它。

In almost all cases you are better off defining

在几乎所有情况下,你最好定义

data Point2 a = Point2 a a deriving (Eq,Ord,Show,Read)

and making each of your instances contingent on the extra information you want.

并使您的每个实例都取决于您想要的额外信息。

instance Num a => Num (Point2 a) where
    ...

instance (Num a, Ord a) => SomeClass (Point2 a) where
    ...

This lets you pass around and construct fewer superfluous dictionaries and increases the number of scenarios in which your Point2 data type can be used.

这使您可以传递并构建更少的多余字典,并增加可以使用Point2数据类型的方案的数量。

On the other hand existential quantification can let you say that you don't care what the type is at all (closer to what you actually requested, type wise) at the expense that you can't use anything on it except for the operations provided by the constraints you specified -- a pretty poor fit here.

另一方面,存在量化可以让你说你根本不关心类型是什么(更接近你实际要求的类型,明智的类型),代价是你不能在它上面使用任何东西,除了提供的操作根据你指定的限制 - 这里非常不合适。

#2


something like this?

这样的事情?

data (Num a, Ord a) => Point2 a = Point2 {
    x :: a
  , y :: a
}

#1


You need to decide if you want an existential or universal quantification on that type. Universal quantification, ala:

您需要决定是否要对该类型进行存在性或通用量化。通用量化,ala:

data (Num a, Ord a) => Point2 a = Point2 a a

yields a proof obligation that Num and Ord instances exist for the type 'a' but doesn't actually help all that much, because all it does is give you an obligation when you go to use the Point class by constructing a value of that type or when you go to pattern match it.

产生了一个证明义务,Num和Ord实例存在于类型'a'但实际上并没有那么多帮助,因为当你通过构造该类型的值来使用Point类时,它所做的就是给你一个义务或者当你去模式匹配它。

In almost all cases you are better off defining

在几乎所有情况下,你最好定义

data Point2 a = Point2 a a deriving (Eq,Ord,Show,Read)

and making each of your instances contingent on the extra information you want.

并使您的每个实例都取决于您想要的额外信息。

instance Num a => Num (Point2 a) where
    ...

instance (Num a, Ord a) => SomeClass (Point2 a) where
    ...

This lets you pass around and construct fewer superfluous dictionaries and increases the number of scenarios in which your Point2 data type can be used.

这使您可以传递并构建更少的多余字典,并增加可以使用Point2数据类型的方案的数量。

On the other hand existential quantification can let you say that you don't care what the type is at all (closer to what you actually requested, type wise) at the expense that you can't use anything on it except for the operations provided by the constraints you specified -- a pretty poor fit here.

另一方面,存在量化可以让你说你根本不关心类型是什么(更接近你实际要求的类型,明智的类型),代价是你不能在它上面使用任何东西,除了提供的操作根据你指定的限制 - 这里非常不合适。

#2


something like this?

这样的事情?

data (Num a, Ord a) => Point2 a = Point2 {
    x :: a
  , y :: a
}