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
相关产品推荐
相关产品推荐

