haskell - 类型类和模块如何交互?

标签 haskell module visibility typeclass

为了掌握更好的类型类(几乎从零开始),我尝试使用面积计算对二维形状进行建模,如下所示:

module TwoDShapes where

class TwoDShape s where
    area :: s -> Float

data Circle = Circle Float deriving Show
aCircle radius | radius < 0 = error "circle radius must be non-negative"
               | otherwise  = Circle radius
instance TwoDShape Circle where
    area (Circle radius) = pi * radius * radius

data Ellipse = Ellipse Float Float deriving Show
anEllipse axis_a axis_b | axis_a < 0 || axis_b < 0 = error "ellipse axis length must be non-negative"
                        | otherwise                = Ellipse axis_a axis_b
instance TwoDShape Ellipse where         
    area (Ellipse axis_a axis_b) = pi * axis_a * axis_b

其他类型的形状依此类推。

这很好,但我想试试这个:
module TwoDShapes  where

class TwoDShape s where
    area :: s -> Float

data TwoDShapeParams = TwoDShapeParams Float Float Float deriving Show

instance TwoDShape TwoDShapeParams where
    area (TwoDShapeParams length_a length_b constant) = foldl (*) 1 [length_a, length_b, constant]

aCircle radius | radius < 0 = error "circle radius must be non-negative"
               | otherwise  = TwoDShapeParams radius radius pi

anEllipse axis_a axis_b | axis_a < 0 || axis_b < 0 = error "ellipse axis length must be non-negative"
                        | otherwise                = TwoDShapeParams axis_a axis_b pi

等等,这也很好。为了隐藏信息,我将模块声明更改为如下所示:
module TwoDShapes (TwoDShape, area, aCircle, anEllipse, aRectangle, aTriangle)

令我惊讶的是,这 1) 工作和 2) 在 ghci aCircle 中计算结果为 TwoDShapeParams 1.0 1.0 3.1415927这是真的,但我不明白类型 TwoDShapeParams在模块外可见。我不确定我在期待什么,但不是这个。

我真正想要的是类型类、它的方法和“智能构造函数”在模块外部可见,没有别的。可以这样做吗?

最佳答案

虽然 TwoDShapes 的表示已隐藏,您已导出 Show例如,它允许 TwoDShapes 类型的任意值转换为 String ,所以这就是信息泄露的来源。真正的抽象类型不应定义 Show例如,或者实际上是 Data类似地暴露有关表示的信息的实例。有一种方法可以将您的类型转换为 String ,只要 String是独立于表示的(参见 ShowData.Map.MapData.Array.Array 实例以获取很好的示例)。

请注意,模块系统正在发挥作用:您仍然不能引用 TwoDShapes定义它的模块之外的构造函数。

关于haskell - 类型类和模块如何交互?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3227891/

相关文章:

module - 无法在 OpenERP 6 中安装新模块

xml - 使用 Perl 模块时的最佳实践

android - 如何设置 android.widget.textview 的可见性选项

Python 2.x - 在同一个类中创建类的静态实例

debugging - Haskell 程序以编程方式获取编译器参数?

haskell - 在这个回合制游戏中使用 Reader monad 是否正确?

haskell - 在第一次出现 x 之前插入元素 y 的函数?

haskell - 无限生成汉明序列的最新技术

menu - OpenERP 在自定义模块中创建子菜单

javascript - CSS 样式可见性未按预期运行