Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell等价于OOP中的类专门化_Oop_Haskell_Inheritance - Fatal编程技术网

Haskell等价于OOP中的类专门化

Haskell等价于OOP中的类专门化,oop,haskell,inheritance,Oop,Haskell,Inheritance,我正在测试一些用于渲染静态体素场景的优化技术,并在此过程中学习一些Haskell。我将体素定义为 type Voxel = ( VoxelId, Position ). 其中,VoxelId只是Int的别名。因为我预期会有一些线性代数,所以我想要位置来表示三维向量。我使用的库()只实现了Matrix数据类型,但将Position作为Matrix的底层类型只会简化进一步的计算,所以我同意这一点 然而,Position不是三维向量没有多大意义,所以我想将Position约束为3x1矩阵,所以当我

我正在测试一些用于渲染静态体素场景的优化技术,并在此过程中学习一些Haskell。我将体素定义为

type Voxel = ( VoxelId, Position ). 
其中,
VoxelId
只是
Int
的别名。因为我预期会有一些线性代数,所以我想要
位置
来表示三维向量。我使用的库()只实现了
Matrix
数据类型,但将Position作为
Matrix
的底层类型只会简化进一步的计算,所以我同意这一点

然而,
Position
不是三维向量没有多大意义,所以我想将
Position
约束为3x1矩阵,所以当我在函数签名中专门使用
Position
时,我保证会出现3x1矩阵或编译错误

<>在C++或其他面向对象语言中,我可以做这样的事情:< /P>
class Matrix
{
  Matrix(int rows, int columns)
  {}
}

class Position : public Matrix
{
  Position()
  : Matrix (3, 1)
  {}
}
当我只希望使用3x1矩阵并在其他地方引用矩阵时,请使用
Position

让我们假设我使用的库中的
Matrix
有一个构造函数

matrix :: (rows) -> (columns) -> Matrix

如何在Haskell中复制此行为而不重新定义
位置
所有操作
矩阵
实现?

在Haskell中,没有像OOP中那样的子类型

您可以定义自己的数据类型

newtype Position = P { unP :: Matrix ... }
   deriving (Show) -- , etc.
还有一个聪明的构造器

position :: Double -> Double -> Double -> Position
position x1 x2 x3 = 
   Position (newMatrix 1 3 [[x1,x2,x3]])  -- pseudo code
如果您确实想隐藏内部表示,可以将上述内容放入其自己的模块中,并仅导出智能构造函数。但是,这样做需要定义并导出此
位置
类型上所需的所有操作,否则它将过于不透明而无法使用

假设不隐藏表示,请注意
Position
Matrix…
是两种不同的类型。因此,您不能将
位置
传递给需要
矩阵的对象。因此,与其

matrixMultiply somePosition someMatrix
需要做的事

matrixMultiply (unP somePosition) someMatrix 
并得到一个
矩阵
结果。如果结果应该是一个
位置
,则可以/需要定义一个自定义乘法函数:

posMultiply :: Position -> Matrix ... -> Position
posMultiply m _ | wrongSize m = error "matrix has the wrong size!"
posMultiply m (Position p) = Position (matrixMultiply m p)
这取决于您想要多少静态保证,可能会有点麻烦。 在许多情况下,它可以减轻疼痛

一个更简单的替代方法是使用一个不使用自定义类型的dumber构造函数。这是一个简单的函数

position :: Double -> Double -> Double -> Matrix ...
position x1 x2 x3 = 
   newMatrix 1 3 [[x1,x2,x3]]  -- pseudo code

在Haskell中构造一个不可变但为空的向量没有什么意义。您可以定义自己的“智能构造函数”(一个基本函数),它只接受例如
(Double,Double,Double)
并返回矩阵。如果希望有更多的静态保证,请将生成的矩阵放入
newtype
包装器中(注意,这还需要定义包装器上的所有矩阵操作,或者每次都展开).为职位重新定义矩阵运算违背了使用第三方库的目的,这是我最后的解决方案。我对原始问题进行了编辑以使其更加清晰。然后每次都必须手动打开,或者使用安全强制。或者像我在下面展示的那样使用一个更愚蠢的构造函数。你的带有子类型的OO示例实际上并没有提供你想要的类型安全性。当然
Position
会自动创建一个3x1矩阵,但是从
matrix
继承的所有实际功能都不知道这一点,并且会很乐意让您尝试只对其他维度有意义的东西。因此,没有必要寻找一种复制的方法。您需要的是一个参数化类型,其中维度在类型中表示:
矩阵行列
。然后您只需定义一个类型同义词
type Position=Matrix 3 1
。这样做需要一些扩展(以获得某种类型的类型级别编号)和适度的高级技术(其中大部分可以在具有相当友好界面的库中实现,但如果没有一些特定的包装器重新实现,可能不会围绕现有的矩阵库进行包装)。谢谢你的回答,我想我现在已经知道如何处理这个问题了,尽管我不得不承认我不是这些解决方案的超级粉丝(它们肯定比我想到的任何东西都要好)。我记得西蒙·佩顿在哈斯克尔的一次演讲中谈到了类型系统的权衡,他在演讲中说了以下几句话:“在Haskell中,向现有类型添加新功能很容易,而在命令式语言中,为新类型提供现有功能很容易,但在这两种情况下,反转都会变得非常混乱”,我想这就是这句话的真实性所在。@Revertlapwing是的,我同意。这就是所谓的。