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,它在你将用于渲染的后端进行参数化.