Ответ 1
Пример:
q1 = newQueue
q2 = enque q1 3
то q1
является отмена q2
, так как все значения неизменяемы. Просто держите ссылку на предыдущее значение.
Я слышал, что одним из преимуществ чисто функциональных структур данных является то, что вы бесплатно выполняете операции отмены/повтора. Может кто-нибудь объяснить, почему? Я не понимаю, почему добавление отмены/повтора упрощено на функциональном языке.
Например, предположим, что у меня есть следующая реализация очереди:
data Queue a = Queue [a] [a]
newQueue :: Queue a
newQueue = Queue [] []
empty :: Queue a -> Bool
empty (Queue [] []) = True
empty _ = False
enqueue :: Queue a -> a -> Queue a
enqueue (Queue xs ys) y = Queue xs (y:ys)
dequeue :: Queue a -> (a, Queue a)
dequeue (Queue [] []) = error "Queue is empty!"
dequeue (Queue [] ys) = dequeue (Queue (reverse ys) [])
dequeue (Queue (x:xs) ys) = (x, Queue xs ys)
Как мне изменить это, чтобы выполнить операции отмены и повтора? (Я мог представить, что функции enqueue и dequeue также возвращают два списка, один из которых содержит все предыдущие версии очереди, а другой список - все будущие версии очереди, и эти списки действуют как наши операции отмены/повтора, но я предполагаю, что это не то, что люди обычно имеют в виду.)
Пример:
q1 = newQueue
q2 = enque q1 3
то q1
является отмена q2
, так как все значения неизменяемы. Просто держите ссылку на предыдущее значение.
Причина undo/redo проще реализовать в чисто функциональном коде из-за двух гарантий:
Вы всегда можете вернуться к старой структуре данных, пока вы поддерживаете ссылку на нее. Если вы хотите сохранить всю историю, вы можете сохранить ее в списке:
trackHistory :: Queue a -> [Queue a] -> [Queue a]
trackHistory currentQueue history = currentQueue : history
Очевидно, что в реальном приложении вы хотели бы ограничить размер истории, но вы получите эту идею. Это работает, потому что вы можете гарантировать, что каждая из очередей в вашем списке не была изменена.