使用堆栈实现撤消和重做功能。如何编辑堆栈而不必在Haskell中重新创建它

问题描述 投票:2回答:1

我有一个名为TextFile的自定义数据类型,它存储了四个字符串,每次编辑文本文件时,我都需要能够将它的一个版本存储在一个堆栈中。这样我就可以实现某种形式的撤销和重做功能。

但是,堆栈将从其他函数中更新,而不是每次都创建一个新的堆栈,当我向它推送东西时,我看不到保存更改的方法?

是否有一种方法可以创建堆栈并在每次推送或弹出某个堆栈时更新相同的堆栈?

newtype Stack a = Stack [a] deriving (Eq, Show)
buffer = Stack [] :: Stack TextFile

data TextFile = TextFile String String String String deriving Show
file = TextFile "This is the left element" " This is the right element" "" ""

pop :: Stack a -> (Maybe a, Stack a)
pop (Stack (x:xs)) = (Just x, Stack xs)
pop (Stack []) = (Nothing, Stack [])

push :: a -> Stack a -> Stack a
push x (Stack xs) = Stack (x:xs)

为了澄清,我的主要问题是如果你不能在Haskell中改变一个变量的值,你如何创建一个堆栈作为一个结构而不重复它?

haskell stack undo redo
1个回答
7
投票

如何创建一个堆栈作为一个结构而不重复它?

您提供的代码很好,不会复制太多数据。

假设你有一堆stack1 = a - b - c - d - e。现在你用代码pop stack1

pop (Stack (x:xs)) = (Just x, Stack xs)

你将返回一个新的堆栈stack2 = b - c - d - e,这是a之后的整个结构,没有任何复制。如果你保持stack1,那么你有两个看起来像这样的结构:

 stack1 -> a - b - c - d - e
               ^
               |
             stack2

请记住,您正在使用的单一链接列表意味着a不是stack2的一部分。如果stack1被垃圾收集,那么你最终会得到stack2 = b - c - d - e,正如你所期望的那样。

现在让我们说你push z stack2屈服于stack3 = z - b - c - d - e。如果stack1stack2仍然存在,那么堆将看起来像:

     stack3 -> z
               |
 stack1 -> a - b - c - d - e
               ^
               |
             stack2
© www.soinside.com 2019 - 2024. All rights reserved.