как написать тип данных Deque в Haskell

#haskell #types #implementation #deque

#haskell #типы #реализация #deque

Вопрос:

как написать в Haskell очередь с двойным завершением («deque»). Структура данных должна иметь функции emptyDeque, front, back, removeFront, removeBack, addFront, addBack и isEmpty, а затем отображать двустороннюю очередь между -> и <- .

это то же самое, но для очереди:

 module Queues (Queue, emptyQueue, front, remove, add, isEmpty)
   newtype Queue a = Queue [a]
   emptyQueue = Queue []
   front  (Queue (x:xs)) = x
   front (Queue []) = error("No front of empty queue")
   add (Queue xs) x = Queue (xs    [x])
   remove (Queue (x:xs)) = Queue xs
   remove (Queue []) = error("Nothing on queue to remove")
   isEmpty (Queue []) = True
   isEmpty (Queue (x:xs)) = False
   showElems [] = ""
   showElems (x:xs) = " "    (Prelude.show x)    (showElems xs)
   showQueue (Queue a) = "<"    (showElems a)    " >"
   instance (Show a) => Show (Queue a) where show = showQueue
  

Я придумал, правильно ли это?

 module Deques (Deque, emptyDeque, front, back, removeFront, removeBack , addFront, addBack, isEmpty)
newtype Deque a = Deque [a]
emptyQueue = Queue []
reverses (x:xs) = (reverses xs)    [x]
front (Deque (x:xs)) = x
front (Deque []) = error("No front of empty Deque")
back (Deque a) = front(reverse(a))
back (Deque []) = error("No back of empty Deque")
addBack (Deque xs) x = Deque (xs    [x])
addFront (Deque xs) x = Deque ([x]    xs)
removeFront (Deque (x:xs)) = Deque xs
removeFront (Deque []) = error("Nothing on Deque to remove")
removeBack (Deque a) = reverses(removeFront(reverses(a))
                 `
  

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

1. Проверьте пакет «deque» в Hackage или прочитайте статью Криса Окасаки » Простые и эффективные чисто функциональные очереди и запросы

2. да, это так, я пытался создать очередь, думая, что с этого было бы проще начать. разве deque не то же самое, что очередь, но с добавлением: back, add back removeback.

3. Попробуйте сохранить два списка, один для начала, а другой для конца. Или просто прочитайте статью Окасаки.

4. @biz: Если вы только что запустили Haskell, то они, вероятно, не ожидают, что вы знаете Okasaki. Ваш back выглядит нормально. Ваш addFront работает (и эффективно), но нет необходимости создавать и объединять список спереди; вы можете просто использовать : .

5. хорошая составная реализация removeBack . Я поражен тем, сколько программистов не используют повторно свой собственный код. Продолжайте так думать 🙂

Ответ №1:

Использование списков для реализации Deque не очень эффективно, но это может сработать. Несколько замечаний

Помимо ошибок типа, вы, похоже, пишете приложение-функцию в стиле других языков

 front(reverse(a))
  

В Haskell скобки предназначены просто для группировки. Более простой способ написания этой строки был бы

 front (reverse a)
  

или даже

 front $ reverse a
  

Еще одно замечание: добавление чего-либо в начало списка очень типично в Haskell

 [x]    xs -- The weird way
x : xs -- The canonical way
  

Однако добавление в конец списка — это некрасиво.

 xs    [x] -- No better way for normal lists. This is inefficient
  

У вас довольно хорошее начало, но вам следует попытаться ознакомиться с уникальной парадигмой и стилем Haskell. Первые несколько глав Learn You a Haskell хорошо справляются с этой задачей.

Ответ №2:

На самом деле вот моя окончательная реализация Deque, которая отлично работает

 module Deques (Deque, emptyDeque, front, back, removeFront, removeBack, addFront, addBack, isEmpty) where

    newtype Deque a = Deque [a]

    backwards (Deque []) = Deque []

    backwards (Deque a) = Deque( reverse a )

    emptyDeque = Deque []

    front (Deque (x:xs)) = x
    front (Deque []) = error("No front of empty Deque")

    back (Deque a) = front( backwards (Deque a))
    back (Deque []) = error("No back of empty Deque")

    addBack (Deque xs) x = Deque (xs    [x])
    addFront (Deque xs) x = Deque (x : xs)

    removeFront (Deque (x:xs)) = Deque xs
    removeFront (Deque []) = error("Nothing on Deque to remove")

    removeBack (Deque a) = backwards( removeFront( backwards (Deque a) ))
    removeBack (Deque []) = error("Nothing on Deque to remove")

    isEmpty (Deque []) = True
    isEmpty (Deque (x:xs)) = False

    showElems [] = ""
    showElems (x:xs) = " "    (Prelude.show x)    (showElems xs)
    showDeque (Deque a) = "<"    (showElems a)    " >"

    instance (Show a) => Show (Deque a) where show = showDeque
  

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

1. addBack равен O (n), поэтому создание большого Deque путем многократного добавления к обратной стороне равно O (n ^ 2). Я думаю, это нормально, если вы никогда этого не сделаете, но тогда в чем смысл Deque?