Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用堆栈实现撤消和重做功能。如何编辑堆栈而不必在Haskell中重新创建它_Haskell_Stack_Undo_Redo - Fatal编程技术网

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

使用堆栈实现撤消和重做功能。如何编辑堆栈而不必在Haskell中重新创建它,haskell,stack,undo,redo,Haskell,Stack,Undo,Redo,我有一个名为TextFile的自定义数据类型,它存储四个字符串,每次编辑文本文件时,我需要能够在堆栈中存储它的一个版本。这样我就可以实现某种形式的撤销和重做功能 但是,堆栈将从其他函数中更新,并且在每次不创建新堆栈的情况下,当我将某些内容推送到堆栈时,我看不到保存更改的方法 有没有一种方法可以让我创建一个堆栈,并在每次推送或弹出某个内容时更新该堆栈 newtype Stack a = Stack [a] deriving (Eq, Show) buffer = Stack [] :: Stack

我有一个名为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中更改变量的值,如何在不复制的情况下创建堆栈作为结构

如何在不复制堆栈的情况下将其创建为结构

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

假设您的当前堆栈为
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
。如果
stack1
stack2
仍处于活动状态,则堆看起来像:

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

这是State monad的一个经典用例,你可以在网上找到很多参考资料。这里是一个非常温和的介绍(甚至有一个用
push
pop
方法建模堆栈的示例,就像你的方法一样)。不过,你需要先了解单子的基本知识。创建一个带有更改的新堆栈和扔掉旧堆栈与更改旧堆栈有什么区别?查找可变与不可变数据结构。您可能仍然需要这里的帮助,在这种情况下,您应该提供有关您遇到的确切问题的更多详细信息(例如,您无法使其完全按照您的要求执行的函数)。但一般来说,试着创建一个新的!(相信我)~扩展我的评论并将其链接到@ATayler的评论不会有什么坏处——你当然可以按照他的方式来做,但手动编写代码以使状态贯穿于你编写的每个函数可能会变得相当乏味。这就是State monad的作用,它只允许您通过将所有样板文件“隐藏在引擎盖下”(在State monad本身的实现中)来编写更清晰的代码。罗宾是完全正确的——就我个人而言,我找到了一个很好的方法来了解例如,州立大学的单子是在思考“有没有一种方法可以把所有这些都清晰地抽象出来?”只有这样,你才能欣赏到解决方案的美丽!(YMMV)。另外,请注意,复制堆栈与编译器实际复制内存中的数据结构之间存在差异。由于值是不可变的,编译器可以让
Stack xs
Stack(x:xs)
在幕后共享对
xs
的引用。