You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 15:09:56