ListZipper 模块

$ cabal install ListZipper
Installed ListZipper-1.2.0.2
Prelude> :m +Data.List.Zipper
Prelude Data.List.Zipper>

Zipper 和 ListZipper

Zipper 是一种带焦点(focus,也称游标, cursor)的数据结构。使用 Zipper 可以很方便的在底层数据结构中进行遍历,更新,插入,删除等操作。

ListZipper 是建立在 List 这种数据结构上的 Zipper,可以理解为带焦点(游标)的List。

ListZipper 函数示例

Prelude Data.List.Zipper> z = fromList [3,4,5]
Prelude Data.List.Zipper> z
Zip [] [3,4,5]
Prelude Data.List.Zipper> replace 6 z
Zip [] [6,4,5]
Prelude Data.List.Zipper> toList z
[3,4,5]
Prelude Data.List.Zipper> emptyp z
False
Prelude Data.List.Zipper> beginp z
True
Prelude Data.List.Zipper> end z
Zip [5,4,3] []
Prelude Data.List.Zipper> cursor z
3
Prelude Data.List.Zipper Data.Function> z & right & right
Zip [4,3] [5]
Prelude Data.List.Zipper Data.Function> z & insert 6
Zip [] [6,3,4,5]
Prelude Data.List.Zipper Data.Function> z & push 6
Zip [6] [3,4,5]
Prelude Data.List.Zipper Data.Function> z & right & pop
Zip [] [4,5]
Prelude Data.List.Zipper Data.Function> z & right & foldrz (\z b -> cursor z + b) 0
9
Prelude Data.List.Zipper Data.Function> z & right & foldlz (\b z -> cursor z + b) 0
9
Prelude Data.List.Zipper> extractz z
3
Prelude Data.List.Zipper> duplicatez z
Zip [] [Zip [] [3,4,5],Zip [3] [4,5],Zip [4,3] [5]]
Prelude Data.List.Zipper> extendz (\z -> show (cursor z)) z
Zip [] ["3","4","5"]
import Control.Monad.State
import Data.List.Zipper f :: State (Zipper Int) [Int]
f = do
modify right -- [3],[4,5]
modify $ replace 6 -- [3],[6,5]
modify $ insert 7 -- [3],[7,6,5]
gets toList -- [3,7,6,5] main = print . evalState f $ fromList [3,4,5]

理解 ListZipper

data Zipper a = Zip ![a] ![a] deriving (Eq,Show)

fromList :: [a] -> Zipper a
fromList as = Zip [] as toList :: Zipper a -> [a]
toList (Zip ls rs) = reverse ls ++ rs left :: Zipper a -> Zipper a
left (Zip (a:ls) rs) = Zip ls (a:rs)
left z = z right :: Zipper a -> Zipper a
right (Zip ls (a:rs)) = Zip (a:ls) rs
right z = z insert :: a -> Zipper a -> Zipper a
insert a (Zip ls rs) = Zip ls (a:rs) delete :: Zipper a -> Zipper a
delete (Zip ls (_:rs)) = Zip ls rs
delete z = z push :: a -> Zipper a -> Zipper a
push a (Zip ls rs) = Zip (a:ls) rs pop :: Zipper a -> Zipper a
pop (Zip (_:ls) rs) = Zip ls rs
pop z = z replace :: a -> Zipper a -> Zipper a
replace a (Zip ls (_:rs)) = Zip ls (a:rs)
replace _ z = z
  • data Zipper a = Zip ![a] ![a] deriving (Eq,Show)

    ListZipper 是建立在List 上的数据结构,它包含两个List,其中第二个List的第一个元素是当前的焦点。

    也就是说左边的 List 包含焦点之前的元素,而右边的 List 则包含焦点及其之后的元素。
  • fromList as = Zip [] as

    fromList 将 List 参数 as 转换成 Zipper,当前焦点在as的第一个元素。
  • toList (Zip ls rs) = reverse ls ++ rs

    toList 将 Zipper 转换成 List。
  • left (Zip (a:ls) rs) = Zip ls (a:rs)

    left 函数将当前焦点左移一个元素。即左边 List 的第一个元素被移至右边 List 的最前端。
  • right (Zip ls (a:rs)) = Zip (a:ls) rs

    right 函数将当前焦点右移一个元素。即右边 List 的第一个元素被移至左边 List 的最前端。
  • insert a (Zip ls rs) = Zip ls (a:rs)

    insert 函数在当前焦点处插入新元素。即在右边 List 的最前端插入新元素。
  • delete (Zip ls (_:rs)) = Zip ls rs

    delete 函数移除处位于焦点处的元素。即右边 List 的第一个元素被移除。
  • push a (Zip ls rs) = Zip (a:ls) rs

    push 函数在当前焦点之前插入新元素。即在左边 List 的最前端插入新元素。
  • pop (Zip (_:ls) rs) = Zip ls rs

    pop 函数移除位于焦点之前的一个元素。即左边 List 的第一个元素被移除。
  • replace a (Zip ls (_:rs)) = Zip ls (a:rs)

    replace 函数替换当前焦点处的元素。即右边 List 的第一个元素被替换。

Haskell语言学习笔记(36)Data.List.Zipper的更多相关文章

  1. Haskell语言学习笔记(88)语言扩展(1)

    ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...

  2. Haskell语言学习笔记(69)Yesod

    Yesod Yesod 是一个使用 Haskell 语言的 Web 框架. 安装 Yesod 首先更新 Haskell Platform 到最新版 (Yesod 依赖的库非常多,版本不一致的话很容易安 ...

  3. Haskell语言学习笔记(20)IORef, STRef

    IORef 一个在IO monad中使用变量的类型. 函数 参数 功能 newIORef 值 新建带初值的引用 readIORef 引用 读取引用的值 writeIORef 引用和值 设置引用的值 m ...

  4. Haskell语言学习笔记(79)lambda演算

    lambda演算 根据维基百科,lambda演算(英语:lambda calculus,λ-calculus)是一套从数学逻辑中发展,以变量绑定和替换的规则,来研究函数如何抽象化定义.函数如何被应用以 ...

  5. Haskell语言学习笔记(39)Category

    Category class Category cat where id :: cat a a (.) :: cat b c -> cat a b -> cat a c instance ...

  6. Haskell语言学习笔记(28)Data.Map

    Map Prelude> import Data.Map as Map Prelude Map> :set -XOverloadedLists Prelude Map> Overlo ...

  7. Haskell语言学习笔记(93)Data.Text

    Data.Text.Read Prelude> :set -XOverloadedStrings Prelude> :m +Data.Text.Read Prelude Data.Text ...

  8. Haskell语言学习笔记(81)Data.Typeable

    Data.Typeable 利用 Data.Typeable,可以打印动态类型信息. class Typeable (a :: k) where typeRep# :: TypeRep a typeR ...

  9. Haskell语言学习笔记(77)Data.HashSet

    安装 unordered-containers $ cabal install unordered-containers Installed unordered-containers-0.2.9.0 ...

随机推荐

  1. 转 JMeter之修改Sampler响应数据的编码格式

    问题:JMeter的sampler响应数据中有中文时,会解析出错. JMeter的Sampler中的响应数据默认的编码格式是:ISO-8859-1.来自文件: jmeter.properties中的语 ...

  2. SSH pts 虚拟终端

    昨天晚上小试了一下SSH,学到了一些乱七八糟的命令,知道了一种古老装逼的聊天方式:write.期间下定决心终于弄明白了pts/0之类的东西到底是什么东西. 先说pts/0吧,man里面是这样说的:pt ...

  3. 知识点查缺补漏贴01-进程间通讯之mmap文件共享

    引文: 个人名言:“同一条河里淹死两次的人,是傻子,淹死三次及三次以上的人是超人”.经历过上次悲催的面试,决定沉下心来,好好的补充一下基础知识点.本文是这一系列第一篇:进程间通讯之mmap. 一.概念 ...

  4. bzoj 1767: [Ceoi2009]harbingers

    Description 给定一颗树,树中每个结点有一个邮递员,每个邮递员要沿着唯一的路径走向capital(1号结点),每到一个城市他可以有两种选择: 1.继续走到下个城市 2.让这个城市的邮递员替他 ...

  5. bzoj4928: 第二题

    Description 对于一棵有根树,定义一个点u的k-子树为u的子树中距离u不超过k的部分. 注意,假如u的子树中不存在距离u为k的点,则u的k-子树是不存在的. 定义两棵子树是相同的,当且仅当不 ...

  6. 更加灵活的编写控制层的方法____结合eval函数

    结合EVAL函数,我们可以把API放到测试用例那边去,就可以使用一个定位元素,测试用例可以使用多个API 发现eval里面可以拼接str.那么写成这样更顺眼     eval("self.d ...

  7. 【转载】CSS + DIV 实现局部布局

    HTML CSS + DIV实现局部布局 1.本章教大家掌握2种布局方式: 1)顶部导航菜单布局,效果图: 2)购物版块布局,效果图: 2.技术目标:使用div + ul-li实现导航菜单布局    ...

  8. ue4 多相机分屏与小地图效果实现教程

    转自:http://blog.csdn.net/shenmifangke/article/details/51940007  通过使用ue4的UI和rendertarget来实现 优点就是可以随意设置 ...

  9. C++并发编成 03 线程同步

    这一节主要讲讲线程同步的方式,C++ 11中提供了丰富的线程同步元语,如condition_variable,futrue,std::packaged_task<>,std::promis ...

  10. javaScript中对象属性的访问

    有两种方式访问对象属性,一个是点操作符(.),一种是中括号操作符([ ]). 当你知道属性的名称时,使用点操作符: var myObj = { prop1: "val1", pro ...