Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

easy "undo" in functional data structures

I've heard that one of the benefits of purely functional data structures is that you get undo/redo operations for free. Can someone explain why? I don't see why adding undo/redo is easier in a functional language.

For example, suppose I have the following implementation of a queue:

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)

How would I modify this to get undo and redo operations? (I could imagine that the enqueue and dequeue functions also return two lists, one of the lists being all the previous versions of the queue and the other list being all the future versions of the queue, and these lists act as our undo/redo operations, but I'm guessing this isn't what people typically have in mind.)

like image 412
grautur Avatar asked Mar 27 '11 03:03

grautur


People also ask

Which data structure is used for undo?

Which data structure is used in redo-undo feature? Explanation: Stack data structure is most suitable to implement redo-undo feature.

How do you implement undo functionality?

To implement Undo , you work backward from the tail of the linked-list, using a 'current-node' pointer or index: where the change was insert , you do a delete but without updating the linked-list; and where it was a delete you insert the data from the data in the linked-list buffer.

How undo and redo works stack?

If “UNDO” string is encountered, pop the top element from Undo stack and push it to Redo stack. If “REDO” string is encountered, pop the top element of Redo stack and push it into the Undo stack. If “READ” string is encountered, print all the elements of the Undo stack in reverse order.

What are undo and redo operations?

The Undo command allows you to discard the most recent change in Quantum Visualizer. The Redo command reverses the most recent change made using Undo. To undo an action, on the Edit menu, click Undo, or press Ctrl + Z. To redo an action, on the Edit menu, click Redo, or press Ctrl +Y.


2 Answers

Example:

q1 = newQueue
q2 = enque q1 3

then q1 is the undo of q2, since all values are immutable. Just keep a reference to the prior value.

like image 109
Kathy Van Stone Avatar answered Sep 20 '22 15:09

Kathy Van Stone


The reason undo/redo is easier to implement in purely functional code is because of two guarantees:

  • operations are side-effect free
  • data structures are immutable

You can always revert back to an old data structure as long as you maintain a reference to it. If you want to store the entire history, you could keep it in a list:

trackHistory :: Queue a -> [Queue a] -> [Queue a]
trackHistory currentQueue history = currentQueue : history

Obviously in a real application you would want to cap the history size, but you get the idea. This works because you can guarantee that each of the queues in your list hasn't been changed.

like image 21
dbyrne Avatar answered Sep 17 '22 15:09

dbyrne