Haskell语言学习笔记(44)Lens(2)
自定义 Lens 和 Isos
-- Some of the examples in this chapter require a few GHC extensions:
-- TemplateHaskell is needed for makeLenses; RankNTypes is needed for
-- a few type signatures later on.
{-# LANGUAGE TemplateHaskell, RankNTypes #-}
import Control.Lens
import Control.Monad.State
data Point = Point
{ _positionX :: Double
, _positionY :: Double
} deriving (Show)
makeLenses ''Point
data Segment = Segment
{ _segmentStart :: Point
, _segmentEnd :: Point
} deriving (Show)
makeLenses ''Segment
makePoint :: (Double, Double) -> Point
makePoint (x, y) = Point x y
makeSegment :: (Double, Double) -> (Double, Double) -> Segment
makeSegment start end = Segment (makePoint start) (makePoint end)
testPoint = makePoint (2,3)
testSeg = makeSegment (0, 1) (2, 4)
pointCoordinates :: Traversal Point Point Double Double
-- :: Applicative f => (Double -> f Double) -> Point -> f Point
pointCoordinates g (Point x y) = Point <$> g x <*> g y
deleteIfNegative x = if x < 0 then Nothing else Just x
extremityCoordinates :: Traversal Segment Segment Double Double
-- :: Applicative f => (Double -> f Double) -> Segment -> f Segment
extremityCoordinates g (Segment start end) =
Segment <$> pointCoordinates g start <*> pointCoordinates g end
scaleSegment :: Double -> Segment -> Segment
scaleSegment x = over extremityCoordinates (x *)
stateExample :: State Segment ()
stateExample = do
segmentStart .= makePoint (0,0)
zoom segmentEnd $ do
positionX += 1
positionY *= 2
pointCoordinates %= negate
unmakePoint :: Point -> (Double, Double)
unmakePoint (Point x y) = (x,y)
pointPair :: Iso' Point (Double, Double)
pointPair = iso unmakePoint makePoint
自定义 Lens 的几个步骤
- {-# LANGUAGE TemplateHaskell, RankNTypes #-}
使用语言扩展 - import Control.Lens
使用Lens库 - data Point = Point { _positionX :: Double, _positionY :: Double }
使用 data 关键字定义数据结构以及字段名,注意字段名必须用下划线开头。 - makeLenses ''Segment
使用 makeLenses ''TypeName 来定义 lens。
自定义 Isos 的几个步骤
- import Control.Lens
使用Lens库 - makePoint :: (Double, Double) -> Point
makePoint (x, y) = Point x y
unmakePoint :: Point -> (Double, Double)
unmakePoint (Point x y) = (x,y)
准备两个输入和输出正好相反的函数。 - pointPair :: Iso' Point (Double, Double)
pointPair = iso unmakePoint makePoint
使用 iso 函数将两者粘合为一个 Iso 。
*Main> view segmentEnd testSeg
Point {_positionX = 2.0, _positionY = 4.0}
*Main> set segmentEnd (makePoint (2, 3)) testSeg
Segment {_segmentStart = Point {_positionX = 0.0, _positionY = 1.0}, _segmentEnd = Point {_positionX = 2.0, _positionY = 3.0}}
*Main> view (segmentEnd . positionY) testSeg
4.0
*Main> over (segmentEnd . positionY) (2 *) testSeg
Segment {_segmentStart = Point {_positionX = 0.0, _positionY = 1.0}, _segmentEnd = Point {_positionX = 2.0, _positionY = 8.0}}
*Main> testSeg ^. segmentEnd
Point {_positionX = 2.0, _positionY = 4.0}
*Main> testSeg & segmentEnd .~ makePoint (2, 3)
Segment {_segmentStart = Point {_positionX = 0.0, _positionY = 1.0}, _segmentEnd = Point {_positionX = 2.0, _positionY = 3.0}}
*Main> testSeg ^. segmentEnd . positionY
4.0
*Main> testSeg & segmentEnd . positionY %~ (2*)
Segment {_segmentStart = Point {_positionX = 0.0, _positionY = 1.0}, _segmentEnd = Point {_positionX = 2.0, _positionY = 8.0}}
(.) 可以用来组合两个lens。
*Main> pointCoordinates deleteIfNegative (makePoint (1, 2))
Just (Point {_positionX = 1.0, _positionY = 2.0})
*Main> pointCoordinates deleteIfNegative (makePoint (-1, 2))
Nothing
*Main> over pointCoordinates negate (makePoint (1, 2))
Point {_positionX = -1.0, _positionY = -2.0}
*Main> set pointCoordinates 7 (makePoint (1, 2))
Point {_positionX = 7.0, _positionY = 7.0}
*Main> toListOf extremityCoordinates (makeSegment (0, 1) (2, 3))
[0.0,1.0,2.0,3.0]
*Main> scaleSegment 2 (makeSegment (0, 1) (2, 3))
Segment {_segmentStart = Point {_positionX = 0.0, _positionY = 2.0}, _segmentEnd = Point {_positionX = 4.0, _positionY = 6.0}}
*Main> execState stateExample (makeSegment (1,2) (5,3))
Segment {_segmentStart = Point {_positionX = 0.0, _positionY = 0.0}, _segmentEnd = Point {_positionX = -6.0, _positionY = -6.0}}
*Main> import Data.Tuple (swap)
*Main Data.Tuple> view pointPair testPoint -- Equivalent to unmakePoint
(2.0,3.0)
*Main Data.Tuple> view (pointPair . _2) testPoint
3.0
*Main Data.Tuple> over pointPair swap testPoint
Point {_positionX = 3.0, _positionY = 2.0}
*Main Data.Tuple> view (from pointPair) (2,3) -- Equivalent to makePoint
Point {_positionX = 2.0, _positionY = 3.0}
*Main Data.Tuple> view (from pointPair . positionY) (2,3)
3.0
自定义 Prisms
{-# LANGUAGE TemplateHaskell, RankNTypes #-}
import Control.Lens
data NewTask =
SimpleTask String |
HarderTask String Int |
CompoundTask String [NewTask]
deriving (Show)
makePrisms ''NewTask
a = SimpleTask "Clean"
b = HarderTask "Clean Kitchen" 15
c = CompoundTask "Clean House" [a,b]
自定义 prisms 的几个步骤
- {-# LANGUAGE TemplateHaskell, RankNTypes #-}
使用语言扩展 - import Control.Lens
使用Lens库 - data NewTask = SimpleTask | HarderTask | CompoundTask
使用 data 关键字定义联合类型。 - makePrisms ''NewTask
使用 makePrisms ''TypeName 来定义 prisms。 - 注意这里的情况和 makeLenses 正相反,字段名没有带下划线,属性名带下划线。
*Main> a ^? _SimpleTask
Just "Clean"
*Main> b ^? _HarderTask
Just ("Clean Kitchen",15)
*Main> b ^? _HarderTask._2
Just 15
*Main> b & _SimpleTask .~ "Clean Garage"
HarderTask "Clean Kitchen" 15
*Main> b & _HarderTask._2 .~ 30
HarderTask "Clean Kitchen" 30
参考链接
Haskell/Lenses and functional references
Control.Lens.Tutorial
A Little Lens Starter Tutorial
Haskell语言学习笔记(44)Lens(2)的更多相关文章
- Haskell语言学习笔记(88)语言扩展(1)
ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...
- Haskell语言学习笔记(79)lambda演算
lambda演算 根据维基百科,lambda演算(英语:lambda calculus,λ-calculus)是一套从数学逻辑中发展,以变量绑定和替换的规则,来研究函数如何抽象化定义.函数如何被应用以 ...
- Haskell语言学习笔记(69)Yesod
Yesod Yesod 是一个使用 Haskell 语言的 Web 框架. 安装 Yesod 首先更新 Haskell Platform 到最新版 (Yesod 依赖的库非常多,版本不一致的话很容易安 ...
- Haskell语言学习笔记(20)IORef, STRef
IORef 一个在IO monad中使用变量的类型. 函数 参数 功能 newIORef 值 新建带初值的引用 readIORef 引用 读取引用的值 writeIORef 引用和值 设置引用的值 m ...
- Haskell语言学习笔记(39)Category
Category class Category cat where id :: cat a a (.) :: cat b c -> cat a b -> cat a c instance ...
- Haskell语言学习笔记(38)Lens(1)
Lens Lens是一个接近语言级别的库,使用它可以方便的读取,设置,修改一个大的数据结构中某一部分的值. view, over, set Prelude> :m +Control.Lens P ...
- Haskell语言学习笔记(64)Lens(4)
安装 lens-tutorial Control.Lens.Tutorial $ cabal install lens-tutorial Installed lens-tutorial-1.0.3 P ...
- Haskell语言学习笔记(56)Lens(3)
手动计算(view, over, set, to, _1) view l = getConst . l Const over l f = runIdentity . l (Identity . f) ...
- Haskell语言学习笔记(72)Free Monad
安装 free 包 $ cabal install free Installed free-5.0.2 Free Monad data Free f a = Pure a | Free (f (Fre ...
随机推荐
- RESTful 知识点
REST(英文:Representational State Transfer,简称REST) 对于资源的具体操作类型,由HTTP动词表示. 常用的HTTP动词有下面五个(括号里是对应的SQL命令). ...
- centos6 yum安装最新版mysql5.7
在看来mysql5.7诸多改进介绍后,决定也安装一个试用下:本文将使用rpm的方式来安装. 环境:OS: CentOS6.5 x86_64 最小化安装MEM: 1GCPU: 1 1. 本文连着上一篇安 ...
- 求幂pow()
pow(x, n) 求x的n次方. 最简单的方法便是计算n个x相乘 public static double pow(double x, int n) { if (n == 0) return 1; ...
- JMeter--详解JMeter配置元件
JMeter配置元件可以用来初始化默认值和变量,以便后续采样器使用.将在其作用域的初始化阶段处理. CSV Data Set Config:被用来从文件中读取数据,并将它们拆分后存储到变量中,适合处理 ...
- Angular 4 路由介绍
Angular 4 路由 1. 创建工程 ng new router --routing 2. 创建home和product组件 ng g component home ng g component ...
- Response、Request、QueryString,修改,Cookies
Response对象:响应请求Response.Write("<script>alert('添加成功!')</script>");Response.Redi ...
- Java堆外内存之二:堆外内存使用总结
目录: <堆外内存操作类ByteBuffer> <DirectBuffer> <Unsafe(java可直接操作内存(),挂起与恢复,CAS操作)> 有时候对内存进 ...
- linux&android PPP 相关知识
Linux&Android PPP相关FAQ 目录 Linux&Android PPP相关FAQ.. 1 一. 文档说明... 3 二. 常见调试技 ...
- API网关Kong系列(一)初识
最近工作需要,加上国内Kong的文章相对缺乏(搜来搜去就那么两篇文章),而且官方文档在某些demo上也有一些过时的地方,遂提笔记录下这些,希望能有帮助. 先随大流介绍下KONG(主要参考官网): 官方 ...
- Hibernate 零散知识点
1 get方法和load方法查询时的区别: 如果在缓存中没有找到相应的对象,get会直接访问数据库并返回一个完全初始化的对象,过程中可能涉及多次数据库调用:而load会返回一个代理对象,只有在对象ge ...