自定义 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 的几个步骤

  1. {-# LANGUAGE TemplateHaskell, RankNTypes #-}

    使用语言扩展
  2. import Control.Lens

    使用Lens库
  3. data Point = Point { _positionX :: Double, _positionY :: Double }

    使用 data 关键字定义数据结构以及字段名,注意字段名必须用下划线开头。
  4. makeLenses ''Segment

    使用 makeLenses ''TypeName 来定义 lens。

自定义 Isos 的几个步骤

  1. import Control.Lens

    使用Lens库
  2. makePoint :: (Double, Double) -> Point

    makePoint (x, y) = Point x y

    unmakePoint :: Point -> (Double, Double)

    unmakePoint (Point x y) = (x,y)

    准备两个输入和输出正好相反的函数。
  3. 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 的几个步骤

  1. {-# LANGUAGE TemplateHaskell, RankNTypes #-}

    使用语言扩展
  2. import Control.Lens

    使用Lens库
  3. data NewTask = SimpleTask | HarderTask | CompoundTask

    使用 data 关键字定义联合类型。
  4. makePrisms ''NewTask

    使用 makePrisms ''TypeName 来定义 prisms。
  5. 注意这里的情况和 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)的更多相关文章

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

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

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

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

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

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

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

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

  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语言学习笔记(38)Lens(1)

    Lens Lens是一个接近语言级别的库,使用它可以方便的读取,设置,修改一个大的数据结构中某一部分的值. view, over, set Prelude> :m +Control.Lens P ...

  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. php 图片剪切

    <?php /** * 图像裁剪 * @param $source_path 原图路径 * @param $target_width 需要裁剪的宽 * @param $target_height ...

  2. Dynamics CRM 2011 报表无法显示的问题总结

    一.一般打开报表会出现:该报表无法显示.(reProcessingAborted)和由于运行Microsoft SQL Server Reporting Services 的服务器上没有安装 Micr ...

  3. Win7 搭建pptpvpn服务器方法

    打开网络与共享中心 选择更改适配器设置 选择菜单文件选项(若无菜单栏,可以按一下alt键就会显示出来的) 选择新建传入链接 选择需要哪些用户可以访问vpn服务器,把勾搭上,点击下一步 注意此处的通过i ...

  4. MySQL的结构图

    MySQL的结构图 为了更好的了解和配置MySQL,就必须先了解一下MySQL的体系结构.如下图所示: ▲MySQL体系架构图 理解MySQL的体系架构对于成功的配置和调试至关重要.以下将对架构图进行 ...

  5. js jquery 设置cookie

    转自http://yaoqianglilan.blog.163.com/blog/static/70978316201091810435251/ 本人亲测setcookie() getcookie() ...

  6. Fatal error: Unable to find local grunt.

    https://stackoverflow.com/questions/15483735/fatal-error-unable-to-find-local-grunt-when-running-gru ...

  7. 异步FIFO空满设计延迟问题

    由于设计的时候读写指针用了至少两级寄存器同步,同步会消耗至少两个时钟周期,势必会使得判断空或满有所延迟,这会不会导致设计出错呢? 异步FIFO通过比较读写指针进行满空判断,但是读写指针属于不同的时钟域 ...

  8. springMVC学习(5)-参数绑定

    接着上一集,记录参数绑定的过程: springmvc中,接收页面提交的数据是通过方法形参来接收: 一.默认支持的类型: 在controller形参中添加如下类型的参数处理适配器会默认识别并进行赋值: ...

  9. (转!)Netdata---Linux系统性能实时监控平台部署

    我一直以为人是慢慢变老的,其实不是,人其实是一瞬间变老的. -------村上春树<舞!舞!舞!> 转自https://www.cnblogs.com/kevingrace/p/73001 ...

  10. solr中facet及facet.pivot理解

    Facet['fæsɪt]很难翻译,只能靠例子来理解了.Solr作者Yonik Seeley也给出更为直接的名字:导航(Guided Navigation).参数化查询(Paramatic Searc ...