在Haskell中对抽象数据类型进行排序

时间:2011-04-27 23:29:54

标签: sorting haskell types sql-order-by

例如我有以下内容,

type something = (Float, Float, Int, Aa, Bb, Cc, Int)

如果我想在他们的第一个元素(Float)中找到最小的something 我该怎么办?我的理由如下,但我无法设法如何实现它

因为我有一个somethings列表,最简单的方法应该是创建我自己的min辅助函数,比较2 somethings并返回两者中最小的一个。然而,它试图以“更简单的方式”让我陷入类型编译错误......

findMin :: something -> something -> somthing
findMin x y = sortBy (compare `on` fst) x y

我不熟悉sortBycompare on,我刚刚在SO中遇到过类似的问题,但我无法使其成功。作为Haskell的初学者,还有另一种方法可以解决这个问题吗?

3 个答案:

答案 0 :(得分:6)

如果要根据数据类型的第一个字段进行比较,可以让Haskell为您编写代码:

data Something = Something Float Float Int String Bool Char Int
               deriving (Eq, Ord)

deriving子句指定为Something类型自动生成的类型类实现。在这里,我们推导出Eq,它允许我们询问两个Something是否相等(例如,==)和Ord,这允许我们比较两个Something 1}}并知道哪一个是“更大”。

派生Ord时Haskell的默认行为是从头到尾比较每个字段,因此默认代码将首先比较每个Float的{​​{1}},这正是你想要的。

在处理实现Something的类型后,您可以使用各种内置函数,例如Ord。这将获取实现minimum :: Ord a => [a] -> a的任何类型的列表,并返回最小的元素。所以,作为一个例子:

Ord

答案 1 :(得分:5)

首先有一些语法错误。

你可以做两件事。首先,遵循使用访问器函数来获取所需字段的模型(fst),我们可以为您的类型字段定义标签:

data Something = Something { field_x, field_y :: Float,
                             field_z    :: Int }

然后按field_x

排序
import Data.List
import Data.Function

sortSomethings :: [Something] -> [Something]
sortSomethings = sortBy (compare `on` field_x)

获得最小值与从排序列表中删除头部相同:

minSomethings  :: [Something] -> Something
minSomethings  = head . sortSomethings

或者,您可以为Ord类型编写自定义Something实例,仅使用field_x,然后定期sortminimum(和其他基于Ord的函数)将“正常工作”。

答案 2 :(得分:5)

使用自定义data类型通常是更好的选择,但如果您真的想使用元组,则可以从定义辅助函数comparingFst开始,该函数根据元组的第一个元素进行比较

import Data.Ord
import Data.List

-- Dummy data types for example purposes. Derive from Show just so
-- that the example can be more easily tested interactively in ghci.
data Aa = Aa deriving Show
data Cc = Cc deriving Show

type Something = (Float, Float, Int, Aa, Cc, Int)

comparingFst :: Something -> Something -> Ordering
comparingFst = comparing fstSomething
    where fstSomething (x,_,_,_,_,_) = x

现在您可以使用以下两个元素中的较小元素:

findMin :: Something -> Something -> Something
findMin x y = case comparingFst x y of
    LT -> x
    _  -> y

或来自元素列表

findMinimum :: [Something] -> Something
findMinimum = minimumBy comparingFst

您还可以使用相同的辅助函数进行排序:

sortSomethings :: [Something] -> [Something]
sortSomethings = sortBy comparingFst

此外,值得一提的是,默认情况下,元组从第一个元素开始按元素进行比较,因此假设AaBb类型可以从Ord派生和Eq,你不需要任何额外的东西,例如:

import Data.List

data Ab = Ab deriving (Show, Ord, Eq)
data Cc = Cc deriving (Show, Ord, Eq)

type Something = (Float, Float, Int, Ab, Cc, Int)

findMin :: Something -> Something -> Something
findMin x y = min x y

findMinimum :: [Something] -> Something
findMinimum = minimum

sortSomethings :: [Something] -> [Something]
sortSomethings = sort

换句话说,您可以按原样使用标准minsort功能。