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. mySQL 教程 第8章 视图

    创建视图的目的 简单 隐藏数据复杂性 安全 可以对视图授权 数据独立 可以屏蔽表结构变化对用户的影响,比如增加列,更改列名 创建视图 1. 创建单表视图 以下视图显示JAVA班的学生姓名.身份证号和班 ...

  2. Json之语法

    JSON 文本格式在语法上与创建 JavaScript 对象的代码相同. 由于这种相似性,无需解析器,JavaScript 程序能够使用内建的 eval() 函数,用 JSON 数据来生成原生的 Ja ...

  3. hadoop框架结构介绍

    近年,随着互联网的发展特别是移动互联网的发展,数据的增长呈现出一种爆炸式的成长势头.单是谷歌的爬虫程序每天下载的网页超过1亿个(2000年数据,)数据的爆炸式增长直接推动了海量数据处理技术的发展.谷歌 ...

  4. Linux中CPU亲和性(go)

    http://www.cnblogs.com/LubinLew/p/cpu_affinity.html

  5. 微信公众号获取粉丝openid系统

    做为一名开发人员,在测试当中也经常需要用到openid,但是微信公众号获取openid的方法也是特别麻烦!网页授权是最常见的方式, 但是网页授权的流程太复杂,不仅要开发,还要在公众号后台设置回调域名( ...

  6. freemarker 宏嵌套nested 的使用

    转载来源:http://blog.sina.com.cn/s/blog_7e5699790100z59g.html 模板页: <#assign basePath = request.contex ...

  7. javascript继承之借用构造函数(二)

    //简单的函数调用 function Father() { this.nums= [1,2]; } function Son() { Father.call(this);//调用超类型,完成son继承 ...

  8. Effect

    /////////////////////////////////shader source/////////////////////////////////Texture2D colorMap : ...

  9. Hive基础之Hive环境搭建

    Hive默认元数据信息存储在Derby里,Derby内置的关系型数据库.单Session的(只支持单客户端连接,两个客户端连接过去会报错): Hive支持将元数据存储在关系型数据库中,比如:Mysql ...

  10. java管道通信

    介绍:不同的数据源之间通过建立管道进行数据通信.如图: 线程之间通信最好的方式就是采用管道机制,类似水管一样,水管可以对接,组合成各种具有过滤性质的管道,管道和线程灵活使用,可以提高效率.(Chann ...