Простая программа сортировки начинающих на Haskell - PullRequest
0 голосов
/ 04 июля 2018

Все еще довольно плохо знаком с Haskell. Я пытаюсь написать функцию сортировки, используя рекурсию, и это то, что я до сих пор:

sort' :: [Int] -> [Int]
sort' [] = []
sort' [x] = [x]
sort' (x:y:xs) = 
  if x > y
    then y:sort' (x:xs)
    else x:sort' (y:xs)

Из того, что я могу сказать, он работает нормально, когда нужно отсортировать менее 2 элементов. Но если я введу [3,2,1], я получу [2,1,3]. Я попытался следовать пути ввода вручную, но я не могу понять, как сортировать больше, чем 2 начальных элемента. Я немного почитал и думал о чем-то, касающемся iterate, и использовал длину списка (length), но я не уверен, как реализовать это, если оно работает.

Ответы [ 2 ]

0 голосов
/ 04 июля 2018

Как заметил @that другой парень, вы можете использовать iterate для применения sort' к списку n раз, что является прекрасным примером использования высокоуровневых комбинаторов в Haskell (в отличие от примитивной рекурсии) , Другим хорошим комбинатором, который полезен для такого рода вещей, является until: until примет предикат :: a -> Bool, функцию :: a -> a и значение :: a и будет применять функцию к значению до тех пор, пока Предикат остается верным. Поэтому, когда вы сталкиваетесь с подобной ситуацией, но не знаете точно, сколько проходов вы хотите сделать на входе, вы можете сделать что-то вроде until isSorted sort' xs, что может быть неплохо.

Многие другие однопроходные алгоритмы сортировки также хороши в Haskell, включая слияния сверху вниз и (особенно) снизу вверх.

Рискуя бросить вас в глубокий конец теории, я хотел бы упомянуть еще один довольно хороший высокоуровневый комбинаторный подход к итерации n раз. Это основано на идее «рекурсивных схем», где основная идея заключается в том, что структура рекурсивного типа данных предоставляет полезные шаблоны для его обработки / преобразования. Как это бывает, Haskell достаточно силен, чтобы выразить многие из этих идей. Один из самых простых примеров схемы рекурсии основан на натуральных числах:

data Nat = Zero | Succ Nat

Это рекурсивный тип данных, поскольку второй конструктор данных ссылается на сам Nat. Есть действительно естественный способ обработки Nat с, то есть, когда у меня есть Zero, я должен вернуть некоторое значение; в противном случае я должен рекурсивно обработать Nat и затем использовать эти значения, чтобы придумать новое значение. Как это бывает, мы можем написать Nat по-другому, что обычно делает это очень просто:

data NatF a = Zero | Succ a
type Nat = Mu NatF

Теперь тип данных NatF может содержать значение любого типа внутри своего «рекурсивного» компонента, а не только другой Nat. Конструктор типа Mu во второй строке в основном похож на функцию fix, но для типов: он создает экземпляр NatF (NatF (NatF (NatF ...))), так что Nat = NatF Nat, что совпадает с нашим предыдущим определением.

Однако из-за возросшей универсальности теперь мы можем записать тип a, который описывает функции, которые обрабатывают Nat s, как описано выше: NatF a -> a. Если дано Zero, функция этого типа просто возвращает some a; когда ему дано Succ, у него есть доступ к a, который он возвратил, когда он был рекурсивно вызван "изнутри" Nat. Оказывается, можно обобщить инфраструктуру, необходимую для этого, чтобы она могла работать с любым типом, написанным в стиле выше (то есть как фиксированная точка типа, обобщенного над рекурсивным компонентом). Это означает, что вы можете просто записать уравнения для вашей функции с учетом результатов рекурсивных вызовов, а затем вызвать cata для этой структуры данных, не заботясь о том, чтобы записывать повторяющиеся скучные рекурсивные вызовы!

Это также означает, что другой способ записать ваши времена "применения сортировки" (длина xs) к xs`:

sort xs = cata phi (toNat $ length xs)
  where phi Zero = xs
        phi (Succ xs) = sort' xs
0 голосов
/ 04 июля 2018

Ваш sort' реализует итерацию пузырьковой сортировки, и из этого следует, что применение ее снова и снова приведет к полностью отсортированному списку. Есть много способов сделать это , один из которых - использовать iterate для многократного применения, и выбрать N-ное приложение, используя !!:

completeSort list = iterate sort' list !! length list
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...