构建 GUI 小部件类的层次结构几乎是面向对象编程中的标准练习。你有某种抽象 Widget
类,具有可以包含其他小部件的小部件的抽象子类,然后您有大量支持文本显示的小部件的进一步抽象类,支持作为输入焦点的小部件,具有 bool 状态的小部件,一直到实际具体的类,例如按钮、 slider 、滚动条、复选框等。
我的问题是:在 Haskell 中执行此操作的最佳方法是什么?
有很多事情使构建 Haskell GUI 变得困难,但这不是我的问题的一部分。在 Haskell 中进行交互式 I/O 有点棘手。实现 GUI 几乎总是意味着为极低级别的 C 或 C++ 库编写包装器。编写此类包装器的人倾向于逐字复制现有的 API(大概是这样任何了解包装库的人都会有宾至如归的感觉)。目前我对这些问题不感兴趣。我完全感兴趣的是如何最好地在 Haskell 中建模子类型多态性。
我们希望从假设的 GUI 库中获得什么样的属性?好吧,我们希望可以随时添加新的小部件类型。 (换句话说,封闭的一组可能的小部件是不好的。)我们希望最大限度地减少代码重复。 (有很多小部件类型!)理想情况下,我们希望能够在必要时规定一种特定的小部件类型,而且还能够在需要时处理任何小部件类型的集合。
在任何自尊的 OO 语言中,上述所有内容当然都是微不足道的。但是在 Haskell 中最好的方法是什么?我可以想到几种方法,但我不确定哪一种是“最好的”。
最佳答案
wxHaskell GUI 库充分利用了 幻象类型 对小部件层次结构进行建模。
想法如下:所有小部件共享相同的实现,即它们是指向 C++ 对象的外部指针。但是,这并不意味着所有小部件都需要具有相同的类型。相反,我们可以像这样构建一个层次结构:
type Object a = ForeignPtr a
data CWindow a
data CControl a
data CButton a
type Window a = Object (CWindow a)
type Control a = Window (CControl a)
type Button a = Control (CButton a)
这样,
Control A
类型的值也匹配类型 Window b
,因此您可以将控件用作窗口,但不能反过来。如您所见,子类型化是通过嵌套类型参数实现的。有关此技术的更多信息,请参阅 Dan Leijen's paper on wxHaskell 中的第 5 节。 .
请注意,这种技术似乎仅限于小部件的实际表示是统一的情况,即始终相同。但是,我相信通过一些想法,它可以扩展到小部件具有不同表示的情况。
特别是,观察到面向对象可以通过在数据类型中包含方法来建模,就像这样
data CWindow a = CWindow
{ close :: IO ()
, ...
}
data CButton a = CButton
{ onClick :: (Mouse -> IO ()) -> IO ()
, ...
}
子类型化可能会在这里节省一些样板,但这不是必需的。
关于haskell - Haskell 中的亚型多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12002979/