轻松“撤消”在函数式数据结构中
我听说纯函数式数据结构的好处之一是您可以免费获得撤消/重做操作。有人可以解释为什么吗?我不明白为什么在函数式语言中添加撤消/重做会更容易。
例如,假设我有以下队列实现:
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)
如何修改它以获取撤消和重做操作? (我可以想象入队和出队函数也返回两个列表,其中一个列表是队列的所有先前版本,另一个列表是队列的所有未来版本,这些列表充当我们的撤消/重做操作,但我猜这不是人们通常想到的。)
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.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
示例:
则
q1
是q2
的撤消,因为所有值都是不可变的。只需保留对先前值的引用即可。Example:
then
q1
is the undo ofq2
, since all values are immutable. Just keep a reference to the prior value.撤消/重做在纯函数代码中更容易实现的原因是因为有两个保证:
只要您维护对旧数据结构的引用,您就可以随时恢复到旧的数据结构。如果您想存储整个历史记录,可以将其保存在列表中:
显然,在真实的应用程序中,您希望限制历史记录的大小,但您明白了。这是可行的,因为您可以保证列表中的每个队列都没有更改。
The reason undo/redo is easier to implement in purely functional code is because of two guarantees:
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:
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.