Haskell中提取公共功能:将三个draw函数合并为一个
在Haskell中复用draw函数的方案
在Haskell里,要实现类似OOP中“抽象接口+通用方法”的逻辑复用,**类型类(Typeclass)**是标准解决方案。它能把不同类型的共性行为抽象出来,让通用逻辑只依赖这些抽象行为,而非具体类型。
步骤1:定义抽象类型类
先把三个VM类型共有的操作抽象成一个类型类,比如命名为DrawableVM,包含draw逻辑需要的所有方法(根据实际代码调整类型细节,比如元素类型、返回值类型):
class DrawableVM vm where rowsAmount :: vm n -> Int -- 获取行数限制 isFocused :: vm n -> Bool -- 判断是否处于聚焦状态 bricksList :: vm n -> [Pair] -- 获取要渲染的列表数据(Pair替换为实际元素类型) something :: Bool -> Pair -> Widget n -- 处理单个元素的逻辑(对应原代码里的StagedListVM.something等)
步骤2:编写通用的draw函数
基于上面的类型类,编写唯一的通用draw函数,逻辑和你原来的三个函数完全一致,但不再依赖具体VM类型:
draw :: (DrawableVM vm, Ord n, Show n) => vm n -> Widget n draw state = vLimit (rowsAmount state) ( renderList ( \_isSelected pairs -> hBox $ map (something _isSelected) pairs ) (isFocused state) (bricksList state) )
步骤3:为每个VM类型实现类型类实例
让三个VM类型分别实现DrawableVM接口,把各自的具体函数绑定到类型类的方法上:
-- StagedListVM的实例 instance DrawableVM StagedListVM where rowsAmount = StagedListVM.rowsAmount isFocused = StagedListVM.isFocused bricksList = StagedListVM.bricksList something = StagedListVM.something -- UnstagedListVM的实例 instance DrawableVM UnstagedListVM where rowsAmount = UnstagedListVM.rowsAmount isFocused = UnstagedListVM.isFocused bricksList = UnstagedListVM.bricksList something = UnstagedListVM.something -- TreeVM的实例 instance DrawableVM TreeVM where rowsAmount = TreeVM.rowsAmount isFocused = TreeVM.isFocused bricksList = TreeVM.bricksList something = TreeVM.something
补充说明
- 类型类的作用类似OOP中的接口,定义了一组必须实现的行为;而实例则对应OOP中的实现类,提供具体行为。
- 如果后续新增类似的VM类型,只需要新增一个
DrawableVM实例,无需修改通用的draw函数,完全符合开闭原则。 - 若原代码中
rowsAmount、bricksList等的类型和示例不符,只需调整类型类中对应方法的类型即可。
内容的提问来源于stack exchange,提问作者Refael Sheinker
相关产品推荐
相关产品推荐

