代码之家  ›  专栏  ›  技术社区  ›  keithb

类型类和模块如何交互?

  •  4
  • keithb  · 技术社区  · 15 年前

    为了掌握更好的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)
    

    令我略感意外的是,这一点在ghci有效 aCircle 计算结果为 TwoDShapeParams 1.0 1.0 3.1415927 TwoDShapeParams 在模块外部可见。我不知道我在期待什么,但不是这个。

    2 回复  |  直到 15 年前
        1
  •  6
  •   Simon Marlow    15 年前

    尽管 TwoDShapes 是隐藏的,你得到了一个 Show 两种形状 转换为 String ,这就是信息泄露的源头。真正的抽象类型不应该定义 例如,或者实际上是 Data 类似地公开有关表示的信息的实例。有办法把你的类型转换成 字符串 ,只要 字符串 显示 实例 Data.Map.Map Data.Array.Array 这方面的好例子)。

    注意,模块系统正在完成它的工作:您仍然不能引用 两种形状 在定义它的模块之外的构造函数。

        2
  •  1
  •   Community CDub    5 年前

    如果你看到 *TwoDShapes 在ghci提示符中,它可以访问模块中的所有内容:

    http://www.haskell.org/ghc/docs/6.12.1/html/users_guide/interactive-evaluation.html

    新的提示符是*Main,这表示我们正在主模块顶层的上下文中键入表达式。我们刚刚加载的模块Main中顶层范围内的所有内容在提示符处也在范围内(可能包括Prelude,只要Main没有显式隐藏它)。

    syntax*module表示模块的完整顶层作用域对在提示符处键入的表达式的作用域起作用。没有*,只有模块的导出是可见的。

    TwoDShapes * 检查一下 aCircle 是。