在我看来,Num
类型类由一个相当任意的函数集合组成。有许多类型自然具有+
和*
操作,但由于abs
、signum
和fromInteger
的存在,作为Num
的实例存在问题。我找不到任何关于这门课背后的设计哲学的讨论,所以我不清楚这里是否有一个合理的理由,或者它是否是一个不幸的历史怪现象。
Matrix
类,其组件是Double
。我显然可以实现+
, *
, -
和negate
。也许fromInteger x
可以给一个1x1 Matrix
与组件Double
值fromInteger x
。如何处理abs
和signum
不太明显,但我可以提出一些满足规则的东西(来自类的文档):
abs x * signum x == x
这个想法的反对意见是,我的Num
实例没有满足人们期望Num
的一些隐含规则。我的*
是一个部分函数(假设Matrix
的大小是一个运行时参数),对于Double
和Int
这样的常见实例来说,情况并非如此。而且不用通勤。无论我为abs
和signum
想出什么,都不会满足每个人的期望。
对这个反对意见的反对意见是,我的Matrix
乘法无论如何都将是一个部分函数(并且在Haskell社区中似乎被接受的这种类型中),那么为什么它特别重要,特别是*
是部分函数?如果我的abs
和signum
满足文档中的规则,那么我就完成了我的交易。任何依赖Num
实例的人都是错误的。
像Matrix
这样的类型应该是Num
的实例吗?
不要为非环创建Num
实例。这太令人困惑了。
Num
函数,他们仍然可以在自己的模块中本地定义它(最好使用简单的newtype
包装器)。
特别是,一般(动态大小)矩阵的Num
实例是有问题的,因为当维度不匹配时不明显会发生什么。你想概括一下什么行为?我认为一个很好的例子是固定二次大小的矩阵(即给定向量空间上的线性自同态)。在这种情况下,乘法显然是组合†,数字文字将被视为常数对角矩阵,因此
1
实际上是乘法单位。就像你在数学背景下写的。
但这与您任意选择数字字面值的大小为1×1的想法是不兼容的!人们期望2 * m
工作,但它崩溃了。与其产生意想不到的结果,不如崩溃;不幸的是,我们很容易想出一些聪明的方法来定义乘法。例如,我们可以对角块复制较小的矩阵,直到它足够大,也许只在1& *;1的情况下这样做……好吧,Matlab做这种特别的东西,但请!我们不要把这种可怕的语言当作什么是好主意的榜样。
如果你有一个明显是加性群的东西,实际上是向量空间,那么让它成为VectorSpace
!如果你也有一个乘法,但它是偏乘法,那么最好只把它定义为一个普通函数。
如果您愿意,您可以为精细交错的数字前奏类定义实例。就我个人而言(尽管我喜欢这个项目的想法),我还不能在任何地方使用它,因为要理解层次结构是相当费力的。
& 还是?麻烦已经开始了,我认为hmatrix实际上在矩阵上实现了*
作为元素明智的乘法。这比Matlab还可怕!