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