简体   繁体   English

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

[英]Sorting abstract datatypes in Haskell

For example I have the following,例如,我有以下内容,

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

If I were to desire to find the smallest something in base to their first element (Float) how could I do that?如果我想在他们的第一个元素(Float)的基础上找到最小的something ,我该怎么做呢? The way I have reasoned it is the following, yet I cant manage to figureout how to implement it我推理它的方式如下,但我无法弄清楚如何实现它

Because I have a list of somethings the easiest way should be to create my own min helper function that compares 2 somethings and returns the smallest of the two.因为我有somethings的列表,所以最简单的方法应该是创建我自己的min助手 function 比较2 somethings并返回两者中最小的一个。 However it is trying to do that "easier way" that got me stuck with type compile errors...然而,它试图做那种让我陷入类型编译错误的“更简单的方法”......

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

I am not familiar with sortBy and compare on , I just came across a similar question here in SO but I couldnt manage to make it work.我不熟悉sortBycompare on ,我刚刚在 SO 中遇到了一个类似的问题,但我无法让它工作。 As a beginner in Haskell, is there another way to approaching this?.作为 Haskell 的初学者,还有其他方法可以解决这个问题吗?

If you want to compare based on the first field of a data type, you can let Haskell write the code for you:如果要根据数据类型的第一个字段进行比较,可以让 Haskell 为您编写代码:

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

The deriving clause specifies which type classes implementations are automatically generated for the Something type. deriving子句指定为Something类型自动生成哪些类型类实现。 Here, we derive Eq which allows us to ask whether two Something s are equal (eg, with == ), and Ord , which allows us to compare two Something s and know which one is "greater".在这里,我们推导出Eq ,它允许我们询问两个Something是否相等(例如,使用== )和Ord ,它允许我们比较两个Something并知道哪个“更大”。

Haskell's default behavior when deriving Ord is to compare each field from first to last, so the default code will start by comparing the first Float of each Something , which is exactly what you want. Haskell 在派生Ord时的默认行为是从第一个到最后一个比较每个字段,因此默认代码将从比较每个Something的第一个Float开始,这正是您想要的。

Once you're dealing with a type that implements Ord , you can use all sorts of built-in functions like minimum:: Ord a => [a] -> a .一旦处理了实现Ord的类型,就可以使用各种内置函数,例如minimum:: Ord a => [a] -> a This takes a list of any type that implements Ord , and gives back the smallest element.这需要一个实现Ord的任何类型的列表,并返回最小的元素。 So, as an example:所以,举个例子:

st1 = Something 3.14 2.72 7 "hello" False 'λ' 42
st2 = Something 3.15 2.72 7 "hello" False 'λ' 42

smallest = minimum [st1,st2]

You have some syntax errors, firstly.首先,您有一些语法错误。

There are two things you can do.你可以做两件事。 Firstly, following the model of using an accessor function to get at the field you want ( fst ), we can define labels for the fields of your type:首先,按照 model 使用访问器 function 获取您想要的字段( fst ),我们可以为您的类型的字段定义标签:

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

and then sort on field_x然后对field_x进行排序

import Data.List
import Data.Function

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

getting at the mimimum is the same as taking the head off the sorted list:达到最小值与从排序列表中取出头部相同:

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

alternatively, you can write a custom Ord instance for the Something type that compares values only using field_x , then regular sort and minimum (and other Ord -based functions), will "just work".或者,您可以为Something类型编写一个自定义Ord实例,该实例仅使用field_x比较值,然后常规sortminimum (以及其他基于Ord的函数)将“正常工作”。

Using a custom data type is usually the better option, but if you really want to use tuples, you can start by defining a helper function comparingFst that compares based on the first element of the tuple.使用自定义data类型通常是更好的选择,但如果您真的想使用元组,您可以从定义一个帮助程序 function comparingFst Fst 开始,它根据元组的第一个元素进行比较。

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

Now you can take the smaller of two elements with:现在您可以使用以下两个元素中较小的一个:

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

or from a list of elements或从元素列表中

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

And you can also use the same helper function for sorting:您还可以使用相同的助手 function 进行排序:

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

Also, it's worth mentioning that tuples are, by default, compared element-wise, starting from the first element, so assuming your Aa and Bb types can be derived from Ord and Eq , you don't need anything extra, ie the example becomes:另外,值得一提的是,默认情况下,元组是从第一个元素开始逐元素比较的,因此假设您的AaBb类型可以从OrdEq派生,您不需要任何额外的东西,即示例变为:

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

In other words, you can just use the standard min and sort functions as-is.换句话说,您可以按原样使用标准的minsort函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM