Lens

Lens是一个接近语言级别的库,使用它可以方便的读取,设置,修改一个大的数据结构中某一部分的值。

view, over, set

Prelude> :m +Control.Lens
Prelude Control.Lens> view _1 ("abc", "def")
"abc"
Prelude Control.Lens> over _1 (++ "!!!") ("abc", "def")
("abc!!!","def")
Prelude Control.Lens> set _1 "!!!" ("abc", "def")
("!!!","def")
Prelude Control.Lens> view _2 ("abc", "def")
"def"

这里 _1, _2 则相当于元组的属性名,在 Lens 库中被称为 lens。

view 是一个 Getting,相当于Java语言中用来读取属性的 .getXXX()。

over 以及 set 是一个 Setting,相当于Java语言中用来设置属性的 .setXXX()。

view l s 读取数据结构 s 中字段 l' 的值。

set l s 设置数据结构 s 中字段 l' 的值。

而 over l f s 则通过调用函数 f 修改数据结构 s 中字段 l' 的值。

view, over, set的操作符版本

Prelude> :m +Control.Lens
Prelude Control.Lens> ("abc", "def") ^. _1
"abc"
Prelude Control.Lens> ("abc", "def") & _1 %~ (++ "!!!")
("abc!!!","def")
Prelude Control.Lens> ("abc", "def") & _1 .~ "!!!"
("!!!","def")
Prelude Control.Lens> ("abc", "def") ^. _2
"def"
Prelude Control.Lens> _2 %~ (++ "***") $ ("abc", "def")
("abc","def***")
Prelude Control.Lens> _2 .~ "***" $ ("abc", "def")
("abc","***")

view l s ≡ s ^. l

set l v s ≡ l .~ v $ s ≡ s & l .~ v

over l f s ≡ l %~ f $ s ≡ s & l %~ f

view, over, set 的 State 版本

Prelude Control.Lens Control.Monad.State> evalState (use _1) ("abc","def")
"abc"
Prelude Control.Lens Control.Monad.State> execState (do _1 .= "!!!"; _2 .= "***") ("abc", "def")
("!!!","***")
Prelude Control.Lens Control.Monad.State> execState (do _1 %= (++ "!!!"); _2 %= (++ "***")) ("abc", "def")
("abc!!!","def***")

preview, review

Prelude Control.Lens> view _Left (Left "abc")
"abc"
Prelude Control.Lens> view _Right (Right "abc")
"abc"
Prelude Control.Lens> view _Just (Just "abc")
"abc"
Prelude Control.Lens> preview _Left (Left "abc")
Just "abc"
Prelude Control.Lens> review _Left "abc"
Left "abc"
  • preview 和 review 函数处理 Either 这样的和类型

    preview 函数向上走一个分支。

    review 函数向下走一个分支。

preview, review 的操作符版本

Prelude Control.Lens> Left "abc" ^?! _Left
"abc"
Prelude Control.Lens> Left "abc" ^? _Left
Just "abc"
Prelude Control.Lens> Right "abc" ^? _Left
Nothing
Prelude Control.Lens> Right "abc" ^? _Right
Just "abc"
Prelude Control.Lens> _Left # "abc"
Left "abc"

preview l x ≡ x ^? l

review l x ≡ l # x

toListOf 及其操作符版本

Prelude Control.Lens> toListOf traverse [1,2,3]
[1,2,3]
Prelude Control.Lens> toListOf (traverse.traverse) [[1,2],[3]]
[1,2,3]
Prelude Control.Lens> toListOf both (1,2)
[1,2]
Prelude Control.Lens> toListOf _1 (4, 1)
[4]
Prelude Control.Lens> [[1,2],[3]] ^..traverse.traverse
[1,2,3]
Prelude Control.Lens> (1,2) ^..both
[1,2]
Prelude Control.Lens> (4, 1) ^.._2
[1]

to

Prelude Control.Lens> view (_1 . to negate) (3,5)
-3
Prelude Control.Lens> (3,5)^._1.to negate
-3
Prelude Control.Lens> views _1 negate (3,5)
-3
Prelude Control.Lens Control.Monad.State> evalState (use (_1 . to negate)) (3,5)
-3
Prelude Control.Lens Control.Monad.State> evalState (uses _1 negate) (3,5)
-3
Prelude Control.Lens> preview (_Just .to (+2)) (Just 3)
Just 5
Prelude Control.Lens> previews _Just (+2) (Just 3)
Just 5

to 操作符可以把普通函数提升为 Getter。

view + to = views

use + to = uses

preview + to = previews

mapped

Prelude Control.Lens> over mapped (+1) [1,2,3]
[2,3,4]
Prelude Control.Lens> set mapped 5 [1,2,3]
[5,5,5]
Prelude Control.Lens> over (mapped._1) (+1) [(1,2),(3,4)]
[(2,2),(4,4)]
Prelude Control.Lens> set (mapped.mapped) 5 [[1],[2]]
[[5],[5]]
Prelude Control.Lens> [[1],[2]] & mapped.mapped .~ 5
[[5],[5]]
Prelude Control.Lens> mapped %~ (+1) $ [1,2,3]
[2,3,4]

mapped 操作符可以把普通函数提升为 Functor。

ix

Prelude Control.Lens> [1,2,3] ^? ix 1
Just 2
Prelude Control.Lens> [1,2,3] ^?! ix 1
2
Prelude Control.Lens> [1,2,3] & (ix 1) .~ 20
[1,20,3]

at

relude Control.Lens> import qualified Data.Map as Map
Prelude Control.Lens Map> Map.fromList [(1,"world")] ^.at 1
Just "world"
Prelude Control.Lens Map> Map.fromList [(1,"world")] ^.ix 1
"world"
Prelude Control.Lens Map> at 1 ?~ "hello" $ Map.empty
fromList [(1,"hello")]
Prelude Control.Lens Map> ix 1 ?~ "hello" $ Map.empty
fromList []

traverse

Prelude Control.Lens> [[1], [2], [3]] ^. traverse
[1,2,3]
Prelude Control.Lens> [1,2,3] ^.. traverse
[1,2,3]
Prelude Control.Lens> [[1], [2], [3]] ^.. traverse . traverse
[1,2,3]

non

Prelude Control.Lens> Just 3 ^. non 1
3
Prelude Control.Lens> Nothing ^. non 1
1

参考链接

Haskell/Lenses and functional references

Control.Lens.Tutorial

A Little Lens Starter Tutorial

Haskell语言学习笔记(38)Lens(1)的更多相关文章

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

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

  2. Haskell语言学习笔记(44)Lens(2)

    自定义 Lens 和 Isos -- Some of the examples in this chapter require a few GHC extensions: -- TemplateHas ...

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

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

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

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

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

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

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

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

  7. Haskell语言学习笔记(64)Lens(4)

    安装 lens-tutorial Control.Lens.Tutorial $ cabal install lens-tutorial Installed lens-tutorial-1.0.3 P ...

  8. Haskell语言学习笔记(56)Lens(3)

    手动计算(view, over, set, to, _1) view l = getConst . l Const over l f = runIdentity . l (Identity . f) ...

  9. Haskell语言学习笔记(72)Free Monad

    安装 free 包 $ cabal install free Installed free-5.0.2 Free Monad data Free f a = Pure a | Free (f (Fre ...

随机推荐

  1. 最新hadoop虚拟机安装教程(附带图文)

    前两天看到有人留言问在什么情况下需要部署hadoop,我给的回答也很简单,就是在需要处理海量数据的时候才需要考虑部署hadoop.关于这个问题在很早之前的一篇分享文档也有说到这个问题,数据量少的完全发 ...

  2. 大快DKhadoop安装教程与常见问题汇总

    上周分别就DKHadoop的安装准备工作以及服务器操作系统配置写了两篇分享的文章,这是个人第一次尝试写一个系统性的分享文章,必然会有很多疏漏的地方,还望见谅吧.今天分享的是DKHadoop安装以及常见 ...

  3. mysql 微信用户昵称emoji 完整保存

    微信用户昵称现在丰富多样,一些个性的名称中经常包含有特殊字符,以及emoji表情.起先,我总以为MySQL只能保存纯文本数据.但其实mysql(5.7版本)已非常强大,完整保存微信用户昵称(emoji ...

  4. Sql Server Report Service 的部署问题

    近期在研究SSRS部署问题,因为以前也用到过SSRS报表,但当时开发的报表是有专门的集成系统的,不需要我自己去部署,所以对这一块的部署也不熟悉,我记得当时我是直接开发出一个SSRS 报表,然后会通过自 ...

  5. System V 消息队列 实例

    前言: 消息队列是消息的链接表,存放在内核中,并由消息队列标识符标识.我们将称消息队列为 “队列”,其标识符为“队列I D”.msgget创建一个新队列或打开一个存在的队列; msgsnd向队列末端添 ...

  6. debian下配置keepalived ha

    抄袭自http://blog.51yip.com/server/1417.html,做了一些修改 可以参考http://blog.linuxphp.org/archives/1615/ 备注:NAT模 ...

  7. bzoj4161: Shlw loves matrixI

    Description 给定数列 {hn}前k项,其后每一项满足 hn = a1*h(n-1) + a2*h(n-2) + ... + ak*h(n-k) 其中 a1,a2...ak 为给定数列.请计 ...

  8. 将ESXI所有的端口组迁移到分布式交换机的步骤

    1.如果是DELL服务器,一般有2-4个网口,那么所有的网口都把网线插到交换机上:2.DELL安装ESXI系统,根据不同的DELL硬件,要安装不同的ESXI版本.原则上越高版本,支持的硬件越多向下兼容 ...

  9. Hibernate cascade级联

    cascade: 级联: 是对象的连锁操作 级联保存(一对多): 级联保存: 当保存双向关系的一方时,默认会报告错误,此时应该在customr中设置级联保存,即操作一个对象时,通过操作其他关联对象 如 ...

  10. ORACLE中index的rebuild(转)

    Oracle里大量删除记录后,表和索引里占用的数据块空间并没有释放. table move可以释放已删除记录表占用的数据块空间,整理碎片.如果将表格用move方式整理碎片后,索引将失效,这时需要将索引 ...