请教下各位大佬,如何用lisp实现如undo和redo的功能?有个办法是把命令保存成字符串,再用eval执行,感觉不是很合适。有没有更正规且灵
活的做法?
--
Lisp-cn(Lisp中文用户组)
CLUG http://lisp.org.cn
On 4月24日, 下午1时26分, Liutos <mat.liu...@gmail.com> wrote:
> 是说写一个编辑器?
>
> 在 2012年4月24日 下午12:07,seagate <xiao.ao.jiang.hu...@gmail.com>写道:
>
> > 请教下各位大佬,如何用lisp实现如undo和redo的功能?有个办法是把命令保存成字符串,再用eval执行,感觉不是很合适。有没有更正规且灵
> > 活的做法?
>
> > --
> > Lisp-cn(Lisp中文用户组)
> > CLUGhttp://lisp.org.cn
On 4月24日, 下午4时20分, Nala Ginrut <nalagin...@gmail.com> wrote:
> 函数是一级对象,为什么不直接保存操作函数?操作保存成字符串是什么考虑?
>
> 2012/4/24 seagate <xiao.ao.jiang.hu...@gmail.com>:
在 2012年4月24日 下午12:07,seagate <xiao.ao.j...@gmail.com> 写道:
> 请教下各位大佬,如何用lisp实现如undo和redo的功能?有个办法是把命令保存成字符串,再用eval执行,感觉不是很合适。有没有更正规且灵
> 活的做法?
>
On 4月24日, 下午4时31分, Jeova Sanctus Unus <jeova.sanctus.u...@gmail.com>
wrote:
> 不是有各种开源的编辑器么?
状态信息可以存在闭包里,不需要通过参数传进去。
不过另一个方案是,undo-list可以实现为一个全局栈,使用circular-list可以实现循环栈。
这样就不需要传入状态变量来控制了。undo操作可以循环,也可以不必。
至于如何存储上一步的数据,就看你怎么设计了,编辑器的话,可以考虑结合页面元数据(colum/line等)来存储增量数据(比如diff那样的效果),如果不用增量方式那这个编辑器就开不了大文件了。
这个就不提供办法了,不然你做下去也没什么乐趣了。
如果不用增量,意味着每次操作都要有一份该文件的拷贝,所以如果有很大的文件就会很占内存。
而且文件很大的话undo一次时间很长。
这种看似弱智的方式也不是没人用,如果写个只针对小数据的undo的话,完全可以采用这种简单方式。
--
Regards,
Zhongye
On 4月24日, 下午7时36分, Xiaofeng Yang <n.akr.aki...@gmail.com> wrote:
> 虽然不知道LZ想要知道什么,不过通常undo/redo可以这样来实现:
>
> * 首先,将所有用户操作封装成一个object。这个object可以是任意数据结构,只要能表达用户的操作,或者,用户操作所导致的改变,即可。
> * 保存一个指针和一个用户操作列表(通常可以实现为一个链表),指针指向用户所进行的最后一个操作所对应的object。
> *
> 用户进行了一个操作的时候,产生一个object来描述该用户的这个操作。用户操作完成后,将这个object添加到用户操作列表里面,就在当前指针所指向的操作之后。并且,改变当前指针,指向这个新的object。
> *
> 如果要undo,那么将指针移动到当前指针所指向的object的前一个object,同时,根据这个object的信息,来将数据回退到当前操作之前的状态。
> * 如果要redo,那么类似undo,指针向后移动一个对象。
>
> P.S. 以上文字,可能有些含糊或者无法准确的表达意思。
>
> Best regards,
> Xiaofeng Yang
>
> 在 2012年4月24日 下午7:16,Nala Ginrut <nalagin...@gmail.com>写道:
>
>
>
>
>
>
>
> > 恩...真的要讨论编辑器实现的话要聊的可就多了...
>
> > 2012/4/24 JIA Zhongye <jia.zhon...@gmail.com>:
Lisp-cn(Lisp中文用户组)--
CLUG http://lisp.org.cn
redo可以指向undo-stack的头元素,对于lisp的话car就可以了。这样避免多余的数据结构。
对于FP来说,由于函数是一级对象,也就是说你可以把一次操作(带状态的函数)当成一个对象来存储,所以undo-list里面只需要存储一系列过程就可以了,不需要存储数据。或者你可以理解成建立一个函数指针类型的堆栈,只不过对于FP来说,由于函数是一级对象,所以不需要依靠函数指针来操作。
循环的话可以直接用circular-list,它相当于一般命令式语言中的循环链表,用它来作为stack,当然自己实现一个也行。
circular-list在Lisp中是否直接提供我不清楚,在Scheme中需要加载srfi-1。
只是想要为自己的代码加入Lispy风味的话,估计有一段时间的适应期才行,可能多写一些Lisp代码就能找到感觉。
怎么才能算够Lispy味,这是个主观的东西。拿排序来说,DP一般采用循环迭代,FP会选用尾递归/map/fold混用来实现,但很多人用Lisp也会用loop/while来写。用Alan
Perlis的话来说,这些都是语法糖,关注这些意义不大。当然,也不是一点用处都没有,至少可以显得很牛。
使用call/cc来实现redo吧!绝对lispy。