为什么在 Haskell 中声明参数化数据类型?
Why parameterised data type declaration in Haskell?
我看了一个 you-tube 视频,了解到有人使用参数化数据类型声明了一个新数据类型:
data Quad a = Quad a a a a
instance (Show a) => Show (Quad a) where
show (Quad a b c d) = (show a) ++ " " ++ -- code continues for printing
我的疑问是为什么我们需要第一行代码。我做了这样的事情,它仍然有效。
我的代码:
data Q = Q Integer Integer Integer Integer
instance Show Q where
show (Q a b c d) = (show a)++" " ++ --code continues for printing
第一行 data Quad a = Quad a a a a
有什么用,而我们可以通过上面显示的方法来完成?请帮忙。提前致谢!
我不知道您对 Java 这样的命令式编程语言有多熟悉,但我假设您对 泛型 很熟悉。现在,您对 Q
的定义或多或少相当于 Java 中的某些内容,例如:
public class Q {
private Integer field1;
private Integer field2;
private Integer field3;
private Integer field4;
public Q (Integer field1, Integer field2, Integer field3, Integer field4) {
this.field1 = field1;
this.field2 = field2;
this.field3 = field3;
this.field4 = field4;
}
}
(是的,我知道 Java 中的 Integer
不等同于 Haskell 中的 Integer
,但这不是问题)。
现在这限制了我们使用 int
s。如果我们想要 quaternion 和 double
s 或 Car
s,可能会出现问题。所以这不会很有效。
Quad
的原始定义在 Java 中是这样的:
public class 四边形<b><A></b> {
私有 <b>A</b> 字段 1;
私有 <b>A</b> 字段 2;
私有 <b>A</b> 字段 3;
私有 <b>A</b> 字段 4;
public 四边形 (<b>A</b> field1, <b>A</b> field2, <b>A</b> field3, <b>A</b> 字段 4) {
this.field1 = field1;
this.field2 = field2;
this.field3 = field3;
this.field4 = field4;
}
}
因此您可以使用 Quad<Integer>
,它或多或少等同于上述 Q
的定义。但是我可以轻松地使用 Quad<Double>
和 Quad<Car>
来构造双打、汽车、马……
的四元数
现在您可能认为马的四元数没有任何意义。四元数通常确实是在数字上指定的。但是有几种数据结构可以表示数字:Integer
s 可以——顾名思义——只能表示整数值。也许你也想允许 Double
s。此外 Integer
可以表示 所有 整数值(直到内存耗尽)。虽然这当然是一个不错的功能,但它需要付出代价:性能。在 Integer
上进行计算通常需要更多时间(即使它们具有 相同的 值)。因此,如果您想提高性能,您可以寻找 Quad Int16
例如。
通过使用类型参数,您可以获得一种灵活性:您不必定义一个看起来与另一个数据类型几乎相同的数据类型。
此外,您可以定义 - 如 Youtube 课程所示 - 对 a
施加约束的类型实例。因此,对于所有 a
可以被 show
编辑的 Quad a
,您可以显示 Quad a
。您还可以对函数施加约束。比如说你想提供一种方法来计算四边形的 "elements" 的总和。您可以定义:
sumquad :: <b>Num a =></b> Quad a -> a
sumquad (Q x y z t) = x + y + z + t
现在您已经为 all Quad a
类型定义了一个 sumquad
函数,其中 a
是 [=35= 的一个实例] typeclass (因此支持加法)。如果我们使用 Q
,Q
应该有一个 sumquadQ
,QDouble
应该有一个 sumquadQDouble
(假设的 data QDouble = QDouble Double Double Double Double
),等等.所以这需要大量的工作并且会导致代码不够优雅
Quad a a a a
允许您创建包含任何类型的四边形,而 Q Integer Integer Integer Integer
只允许整数。
所以这取决于你的四核能存储什么。如果你只存储整数,也许它应该被称为 IntegerQuad。一个原因可能是你想实现一个像
这样的函数
--collapse :: Q -> Integer
collapse Q(a,b,c,d) = a+b+c+d
除非指定了 (+),否则无法执行此操作。
在 Haskell 中,我认为您应该尽可能抽象,因为这会给您最大的灵活性,并且最有可能重用其他功能。
我看了一个 you-tube 视频,了解到有人使用参数化数据类型声明了一个新数据类型:
data Quad a = Quad a a a a
instance (Show a) => Show (Quad a) where
show (Quad a b c d) = (show a) ++ " " ++ -- code continues for printing
我的疑问是为什么我们需要第一行代码。我做了这样的事情,它仍然有效。 我的代码:
data Q = Q Integer Integer Integer Integer
instance Show Q where
show (Q a b c d) = (show a)++" " ++ --code continues for printing
第一行 data Quad a = Quad a a a a
有什么用,而我们可以通过上面显示的方法来完成?请帮忙。提前致谢!
我不知道您对 Java 这样的命令式编程语言有多熟悉,但我假设您对 泛型 很熟悉。现在,您对 Q
的定义或多或少相当于 Java 中的某些内容,例如:
public class Q {
private Integer field1;
private Integer field2;
private Integer field3;
private Integer field4;
public Q (Integer field1, Integer field2, Integer field3, Integer field4) {
this.field1 = field1;
this.field2 = field2;
this.field3 = field3;
this.field4 = field4;
}
}
(是的,我知道 Java 中的 Integer
不等同于 Haskell 中的 Integer
,但这不是问题)。
现在这限制了我们使用 int
s。如果我们想要 quaternion 和 double
s 或 Car
s,可能会出现问题。所以这不会很有效。
Quad
的原始定义在 Java 中是这样的:
public class 四边形<b><A></b> {
私有 <b>A</b> 字段 1;
私有 <b>A</b> 字段 2;
私有 <b>A</b> 字段 3;
私有 <b>A</b> 字段 4;
public 四边形 (<b>A</b> field1, <b>A</b> field2, <b>A</b> field3, <b>A</b> 字段 4) {
this.field1 = field1;
this.field2 = field2;
this.field3 = field3;
this.field4 = field4;
}
}
因此您可以使用 Quad<Integer>
,它或多或少等同于上述 Q
的定义。但是我可以轻松地使用 Quad<Double>
和 Quad<Car>
来构造双打、汽车、马……
现在您可能认为马的四元数没有任何意义。四元数通常确实是在数字上指定的。但是有几种数据结构可以表示数字:Integer
s 可以——顾名思义——只能表示整数值。也许你也想允许 Double
s。此外 Integer
可以表示 所有 整数值(直到内存耗尽)。虽然这当然是一个不错的功能,但它需要付出代价:性能。在 Integer
上进行计算通常需要更多时间(即使它们具有 相同的 值)。因此,如果您想提高性能,您可以寻找 Quad Int16
例如。
通过使用类型参数,您可以获得一种灵活性:您不必定义一个看起来与另一个数据类型几乎相同的数据类型。
此外,您可以定义 - 如 Youtube 课程所示 - 对 a
施加约束的类型实例。因此,对于所有 a
可以被 show
编辑的 Quad a
,您可以显示 Quad a
。您还可以对函数施加约束。比如说你想提供一种方法来计算四边形的 "elements" 的总和。您可以定义:
sumquad :: <b>Num a =></b> Quad a -> a
sumquad (Q x y z t) = x + y + z + t
现在您已经为 all Quad a
类型定义了一个 sumquad
函数,其中 a
是 [=35= 的一个实例] typeclass (因此支持加法)。如果我们使用 Q
,Q
应该有一个 sumquadQ
,QDouble
应该有一个 sumquadQDouble
(假设的 data QDouble = QDouble Double Double Double Double
),等等.所以这需要大量的工作并且会导致代码不够优雅
Quad a a a a
允许您创建包含任何类型的四边形,而 Q Integer Integer Integer Integer
只允许整数。
所以这取决于你的四核能存储什么。如果你只存储整数,也许它应该被称为 IntegerQuad。一个原因可能是你想实现一个像
这样的函数--collapse :: Q -> Integer
collapse Q(a,b,c,d) = a+b+c+d
除非指定了 (+),否则无法执行此操作。
在 Haskell 中,我认为您应该尽可能抽象,因为这会给您最大的灵活性,并且最有可能重用其他功能。