2014-10-07 54 views
7

我看到的大部分Haskell代码都使用直接结构,如列表和树。例如,它是很常见的Haskeller写:Haskell中OCaml模块的等价物是什么?

fillRect :: Color → Bounds → Image → Image 

这种模式有一个问题:假如以后程序员决定修改的“图像”的定义,或使用其他数据结构,那么他将必须重构使用它的每一段代码。在OCaml中,您可以简单地使用指定图像接口的模块,然后再决定具体的实现。

什么是Haskell替代OCaml的模块?

+0

该类型签名是如何表示'fillRect'使用(或者甚至可以访问)'Image'类型的实现细节?你如何在OCaml中写出不同的签名(除了明显的语法差异和不同的命名约定)? – sepp2k 2014-10-07 23:52:14

+6

[这是Haskell模拟](http://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/)。它不像Ocaml模块那么强大(至少不是没有很多扩展),但它涵盖了最常见的用例。只需在支持这些操作的类型上记录多态函数。 – 2014-10-08 00:03:59

+2

背包是为了将某种形式的模块导入Haskell - http://plv.mpi-sws.org/backpack/ – nlucaroni 2014-10-08 13:45:18

回答

10

有几种选择;没有一个完全符合ML模块,但每个方面都是。

  • 参数多态性。关于Image中的功能,请参数化Image类型的 -constructor,而不是指定您的模块和其中的fillRect功能,而不是指定图像的特定“种类”。所以这将是像

    fillRect_ppm :: ImageImplemetation i => Colour -> Bounds -> Image i -> Image i 
    

    的签名,其中ImageImplemetation是某种类型的类,它指定类似的转换和/或后端功能。
    有了这样的解决方案,你不能真的完全取代Image类型,但你可以使类型本身任意灵活。很可能,您将用于Image的所有具体类型实际上都会共享一些字段,因此最好不要使它比所需的更灵活:ImageImplemetation的不同实例只需实现它们之间不同的不同的。如果这些实现非常相似,那么您可能想要仅对像颜色空间这样的细节进行参数化。
    当然你需要提前计划一下这个解决方案,但只是为了一个通用的界面。如果你定义了必要的实例,你仍然可以在后面的任何类型作为参数。

  • 类似的(也可能混合),你可以只为类型的类型类,它可以保存图像数据

    fillRect_tcl :: Image img => Colour -> Bounds -> img -> img 
    

    Image类将直接定义一些像元如何画线,并fillRect_tcl将在其执行使用这些。好,因为fillRect_tcl立即与任何这样的类型工作。有什么不好的是,Image类将需要相当笨拙(它的首选使用类型类的“数学”的东西与简单和非常明确的法律)。

    • 也许类甚至可以有矩形的方法:

      class Image img where 
          ... 
          fillRect_tcm :: Colour -> Bounds -> img -> img 
          ... 
      

      不是很好的,你需要完全重新定义了任何img实例方法。

  • Haskell的模块系统不能做了很多,但仍然是有时不足以使你从保存重构一切。举例来说,如果Image从模块Data.Image来了,你可以做

    import qualified Data.Image as IM 
    
    fillRect_qfi :: Colour -> Bounds -> IM.Image -> IM.Image 
    

    ,并使用该模块中定义的所有功能外,还通过预选赛。如果您在某个时候决定切换实施,则可以更改导入。
    当然,这对转换并不是很好,但是对于一次性更改而言确实很不错。

很适合你的例子:diagrams同时使用第一点;例如rect使用TrailLike类来实现其基元,并且该类包括类型为QDiagram的“最终”图,该图在您将用于渲染的后端进行参数化。

相关问题