在Haskell中OCaml模块的等价物是什么?

Mai*_*tor 9 ocaml haskell module

我看到的大多数Haskell代码都使用了直接结构,例如列表和树.例如,Haskeller通常会写:

fillRect :: Color ? Bounds ? Image ? Image
Run Code Online (Sandbox Code Playgroud)

该模式存在一个问题:如果稍后程序员决定修改"Image"的定义,或者使用其他数据结构,那么他将不得不使用它重构每一段代码.在OCaml中,您可以简单地使用指定Image接口的模块,然后决定稍后的具体实现.

什么是OCaskl模块的Haskell替代品?

lef*_*out 12

有几种选择; 没有完全匹配ML模块,但每个方面都是如此.

  • 参数多态性.您可以参考抽象类型 - 构造fillRect函数来指定图像的特定"种类",而不是参数化模块及其中的函数.所以这将是一个签名ImageImage

    fillRect_ppm :: ImageImplemetation i => Colour -> Bounds -> Image i -> Image i
    
    Run Code Online (Sandbox Code Playgroud)

    哪个ImageImplemetation是类型类,它指定了转换和/或后端函数之类的东西.
    有了这样的解决方案,你不能真正取代Image完全的类型,但你可以使该类型本身随意灵活.可能,您将要使用的所有具体类型Image实际上将共享一些字段,因此最好不要使它比必要更灵活:不同的实例ImageImplemetation只需要实现它们之间的不同.如果实现非常相似,您可能希望仅对颜色空间等一些细节进行参数化.
    当然,您需要使用此解决方案提前计划,但仅限于通用接口.如果定义了必要的实例,您仍然可以在以后添加任何类型作为参数.

  • 类似地(并且可以混合),您可以只为可以保存图像数据的类型设置类型类.

    fillRect_tcl :: Image img => Colour -> Bounds -> img -> img
    
    Run Code Online (Sandbox Code Playgroud)

    Image班将直接定义一些像元如何画线,并fillRect_tcl会在其执行使用这些.好,因为fillRect_tcl任何这样的类型立即工作.有点不好的是,这个Image类需要相当笨拙(最好使用类型类来表示"数学"的东西,并且有简单明确的法则).

    • 也许该类甚至可以使用矩形作为方法:

      class Image img where
        ...
        fillRect_tcm :: Colour -> Bounds -> img -> img
        ...
      
      Run Code Online (Sandbox Code Playgroud)

      不太好,你需要为任何img实例完全重新定义该方法.

  • Haskell的模块系统不能做很多事情,但它有时足以让你免于重构一切.例如,如果Image来自一个模块Data.Image,你可以做到

    import qualified Data.Image as IM
    
    fillRect_qfi :: Colour -> Bounds -> IM.Image -> IM.Image
    
    Run Code Online (Sandbox Code Playgroud)

    并使用限定符中使用该模块中定义的所有函数.如果在某些时候您决定切换实现,您只需更改导入即可.
    当然,这对于定期切换类型并不是很好,但对于一次性更改则相当不错.

非常适合您的示例:图表使用了第一点; 例如,rect使用一个TrailLike类来实现它的基元,这个类包含"最终"图表类型QDiagram,它在你将用于渲染的后端进行参数化.