[英]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.我不熟悉sortBy
和compare 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
比较值,然后常规sort
和minimum
(以及其他基于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:另外,值得一提的是,默认情况下,元组是从第一个元素开始逐元素比较的,因此假设您的Aa
和Bb
类型可以从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
In other words, you can just use the standard min
and sort
functions as-is.换句话说,您可以按原样使用标准的min
和sort
函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.