Сортировка абстрактных типов данных в Haskell

#sorting #haskell #types #sql-order-by

#сортировка #haskell #типы #sql-порядок по

Вопрос:

Например, у меня есть следующее,

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

Если бы я захотел найти наименьший something в базе для их первого элемента (Float), как я мог бы это сделать? Я аргументировал это следующим образом, но мне не удается выяснить, как это реализовать

Поскольку у меня есть список, somethings самым простым способом должно быть создание моей собственной min вспомогательной функции, которая сравнивает 2 somethings и возвращает наименьший из двух. Однако он пытается сделать это «более простым способом», из-за которого я застрял с ошибками компиляции типа

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

Я не знаком с sortBy и compare on , я только что наткнулся на аналогичный вопрос здесь, в SO, но мне не удалось заставить его работать. Как новичок в Haskell, есть ли другой способ приблизиться к этому?.

Комментарии:

1. «fst» и «snd» работают только с кортежами с двумя элементами. Для чего-либо более длинного вам, вероятно, лучше использовать «data Something = …», как предлагали другие.

Ответ №1:

Если вы хотите сравнить на основе первого поля типа данных, вы можете позволить Haskell написать код за вас:

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

deriving Предложение указывает, реализации классов типов автоматически генерируются для Something типа. Здесь мы выводим, Eq который позволяет нам спросить, равны ли два Something s (например, с == ), и Ord , который позволяет нам сравнить два Something s и узнать, какой из них «больше».

Поведение Haskell по умолчанию при выводе Ord заключается в сравнении каждого поля от первого до последнего, поэтому код по умолчанию будет начинаться с сравнения первого Float из каждого Something , что является именно тем, что вы хотите.

Как только вы имеете дело с типом, который реализует Ord , вы можете использовать всевозможные встроенные функции, такие как minimum :: Ord a => [a] -> a . Это принимает список любого типа, который реализует Ord , и возвращает наименьший элемент. Итак, в качестве примера:

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

smallest = minimum [st1,st2]
  

Ответ №2:

Обычно лучшим вариантом является использование пользовательского 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  

Также стоит упомянуть, что кортежи по умолчанию сравниваются поэлементно, начиная с первого элемента, поэтому, предполагая, что ваши типы 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  

Другими словами, вы можете просто использовать стандартные min и sort функции как есть.

Ответ №3:

Во-первых, у вас есть некоторые синтаксические ошибки.

Вы можете сделать две вещи. Во-первых, следуя модели использования функции доступа для получения нужного поля ( 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 , тогда обычные sort и minimum (и другие Ord функции на основе) будут «просто работать».

Комментарии:

1. Кроме того, comparing является compare on