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

Haskell自定义数据类型列表快速排序实现问题:按构造器排序

Haskell自定义数据类型列表的快速排序实现

问题背景

你定义了如下Haskell自定义数据类型:

data Cuidado = Comprar String Int | Medicar String

尝试用快速排序实现排序函数valCui,代码如下:

valCui :: [Cuidado] -> [Cuidado]
valCui [] = []
valCui (x:xs) = valCui [a | a <- xs, x > a] ++ [x] ++ valCui [a | a <- xs, x <= a]

但代码无法正常运行,期望实现的效果是:

valCui [Medicar "med7", Comprar "med4" 30] == [Comprar "med4" 30, Medicar "med7"]

问题原因

代码报错的核心是Haskell不会默认给自定义数据类型生成>、<=这类比较运算符,这些运算符属于Ord类型类的范畴,需要显式为Cuidado类型提供该类的实现,或者在排序逻辑中直接定义比较规则。

解决方案

方案一:自动派生Ord类型类

如果接受按构造器定义顺序排序(Comprar因为定义在前,会被视为比Medicar小),可以直接在数据类型定义时派生Eq和Ord(Ord依赖Eq):

data Cuidado = Comprar String Int | Medicar String deriving (Eq, Ord)

派生后,Haskell会自动生成比较规则:

  • 不同构造器:定义靠前的构造器更小(即Comprar < Medicar)
  • 相同构造器:按字段依次比较(比如两个Comprar会先比字符串,再比整数)
    此时你的原valCui代码就能直接正常运行。

方案二:手动实现Ord类型类(自定义排序规则)

如果需要自定义排序逻辑(比如忽略构造器,只按药品名称排序),可以手动实现Ord:

data Cuidado = Comprar String Int | Medicar String deriving (Eq)

instance Ord Cuidado where
    -- 按药品名称比较,不管构造器
    compare (Comprar name1 _) (Comprar name2 _) = compare name1 name2
    compare (Comprar name1 _) (Medicar name2) = compare name1 name2
    compare (Medicar name1) (Comprar name2 _) = compare name1 name2
    compare (Medicar name1) (Medicar name2) = compare name1 name2

实现后,原valCui函数依然可以正常使用。

方案三:在快速排序中直接嵌入比较逻辑

如果不想依赖Ord类型类,也可以直接修改valCui函数,在内部定义比较规则:

valCui :: [Cuidado] -> [Cuidado]
valCui [] = []
valCui (x:xs) = valCui [a | a <- xs, isLess a x] ++ [x] ++ valCui [a | a <- xs, not (isLess a x)]
  where
    -- 自定义比较规则:Comprar < Medicar,同构造器按名称排序
    isLess :: Cuidado -> Cuidado -> Bool
    isLess (Comprar n1 _) (Medicar _) = True
    isLess (Medicar _) (Comprar _ _) = False
    isLess (Comprar n1 _) (Comprar n2 _) = n1 < n2
    isLess (Medicar n1) (Medicar n2) = n1 < n2

这个版本不需要派生任何类型类,直接在函数内实现比较逻辑,同样能满足你的需求。

内容的提问来源于stack exchange,提问作者Gabriel Brito de França

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 09:15:34