自定义 Lens 和 Isos

  1. -- Some of the examples in this chapter require a few GHC extensions:
  2. -- TemplateHaskell is needed for makeLenses; RankNTypes is needed for
  3. -- a few type signatures later on.
  4. {-# LANGUAGE TemplateHaskell, RankNTypes #-}
  5. import Control.Lens
  6. import Control.Monad.State
  7. data Point = Point
  8. { _positionX :: Double
  9. , _positionY :: Double
  10. } deriving (Show)
  11. makeLenses ''Point
  12. data Segment = Segment
  13. { _segmentStart :: Point
  14. , _segmentEnd :: Point
  15. } deriving (Show)
  16. makeLenses ''Segment
  17. makePoint :: (Double, Double) -> Point
  18. makePoint (x, y) = Point x y
  19. makeSegment :: (Double, Double) -> (Double, Double) -> Segment
  20. makeSegment start end = Segment (makePoint start) (makePoint end)
  21. testPoint = makePoint (2,3)
  22. testSeg = makeSegment (0, 1) (2, 4)
  23. pointCoordinates :: Traversal Point Point Double Double
  24. -- :: Applicative f => (Double -> f Double) -> Point -> f Point
  25. pointCoordinates g (Point x y) = Point <$> g x <*> g y
  26. deleteIfNegative x = if x < 0 then Nothing else Just x
  27. extremityCoordinates :: Traversal Segment Segment Double Double
  28. -- :: Applicative f => (Double -> f Double) -> Segment -> f Segment
  29. extremityCoordinates g (Segment start end) =
  30. Segment <$> pointCoordinates g start <*> pointCoordinates g end
  31. scaleSegment :: Double -> Segment -> Segment
  32. scaleSegment x = over extremityCoordinates (x *)
  33. stateExample :: State Segment ()
  34. stateExample = do
  35. segmentStart .= makePoint (0,0)
  36. zoom segmentEnd $ do
  37. positionX += 1
  38. positionY *= 2
  39. pointCoordinates %= negate
  40. unmakePoint :: Point -> (Double, Double)
  41. unmakePoint (Point x y) = (x,y)
  42. pointPair :: Iso' Point (Double, Double)
  43. 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 。
  1. *Main> view segmentEnd testSeg
  2. Point {_positionX = 2.0, _positionY = 4.0}
  3. *Main> set segmentEnd (makePoint (2, 3)) testSeg
  4. Segment {_segmentStart = Point {_positionX = 0.0, _positionY = 1.0}, _segmentEnd = Point {_positionX = 2.0, _positionY = 3.0}}
  5. *Main> view (segmentEnd . positionY) testSeg
  6. 4.0
  7. *Main> over (segmentEnd . positionY) (2 *) testSeg
  8. Segment {_segmentStart = Point {_positionX = 0.0, _positionY = 1.0}, _segmentEnd = Point {_positionX = 2.0, _positionY = 8.0}}
  9. *Main> testSeg ^. segmentEnd
  10. Point {_positionX = 2.0, _positionY = 4.0}
  11. *Main> testSeg & segmentEnd .~ makePoint (2, 3)
  12. Segment {_segmentStart = Point {_positionX = 0.0, _positionY = 1.0}, _segmentEnd = Point {_positionX = 2.0, _positionY = 3.0}}
  13. *Main> testSeg ^. segmentEnd . positionY
  14. 4.0
  15. *Main> testSeg & segmentEnd . positionY %~ (2*)
  16. Segment {_segmentStart = Point {_positionX = 0.0, _positionY = 1.0}, _segmentEnd = Point {_positionX = 2.0, _positionY = 8.0}}

(.) 可以用来组合两个lens。

  1. *Main> pointCoordinates deleteIfNegative (makePoint (1, 2))
  2. Just (Point {_positionX = 1.0, _positionY = 2.0})
  3. *Main> pointCoordinates deleteIfNegative (makePoint (-1, 2))
  4. Nothing
  5. *Main> over pointCoordinates negate (makePoint (1, 2))
  6. Point {_positionX = -1.0, _positionY = -2.0}
  7. *Main> set pointCoordinates 7 (makePoint (1, 2))
  8. Point {_positionX = 7.0, _positionY = 7.0}
  9. *Main> toListOf extremityCoordinates (makeSegment (0, 1) (2, 3))
  10. [0.0,1.0,2.0,3.0]
  11. *Main> scaleSegment 2 (makeSegment (0, 1) (2, 3))
  12. Segment {_segmentStart = Point {_positionX = 0.0, _positionY = 2.0}, _segmentEnd = Point {_positionX = 4.0, _positionY = 6.0}}
  13. *Main> execState stateExample (makeSegment (1,2) (5,3))
  14. Segment {_segmentStart = Point {_positionX = 0.0, _positionY = 0.0}, _segmentEnd = Point {_positionX = -6.0, _positionY = -6.0}}
  1. *Main> import Data.Tuple (swap)
  2. *Main Data.Tuple> view pointPair testPoint -- Equivalent to unmakePoint
  3. (2.0,3.0)
  4. *Main Data.Tuple> view (pointPair . _2) testPoint
  5. 3.0
  6. *Main Data.Tuple> over pointPair swap testPoint
  7. Point {_positionX = 3.0, _positionY = 2.0}
  8. *Main Data.Tuple> view (from pointPair) (2,3) -- Equivalent to makePoint
  9. Point {_positionX = 2.0, _positionY = 3.0}
  10. *Main Data.Tuple> view (from pointPair . positionY) (2,3)
  11. 3.0

自定义 Prisms

  1. {-# LANGUAGE TemplateHaskell, RankNTypes #-}
  2. import Control.Lens
  3. data NewTask =
  4. SimpleTask String |
  5. HarderTask String Int |
  6. CompoundTask String [NewTask]
  7. deriving (Show)
  8. makePrisms ''NewTask
  9. a = SimpleTask "Clean"
  10. b = HarderTask "Clean Kitchen" 15
  11. 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 正相反,字段名没有带下划线,属性名带下划线。
  1. *Main> a ^? _SimpleTask
  2. Just "Clean"
  3. *Main> b ^? _HarderTask
  4. Just ("Clean Kitchen",15)
  5. *Main> b ^? _HarderTask._2
  6. Just 15
  7. *Main> b & _SimpleTask .~ "Clean Garage"
  8. HarderTask "Clean Kitchen" 15
  9. *Main> b & _HarderTask._2 .~ 30
  10. 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. jquery dataTable的学习

    http://www.cnblogs.com/nier/archive/2012/03/19/2406450.html 分页 bPaginite:true;是否启用分页功能 sPaginationTy ...

  2. view的setTag() 和 getTag()应用 ViewHolder

    转自 http://www.cnblogs.com/qingblog/archive/2012/07/03/2575140.html View中的setTag(Onbect)表示给View添加一个格外 ...

  3. TraceView 使用详解 android eclipse

    先看命令 (配置好环境变量的情况下,直接traceview+空格+ trace文件路径即可): TraceView是什么 Traceview是android平台配备一个很好的性能分析的工具.它可以通过 ...

  4. 【Hibernate学习笔记-5.1】使用@Transient修饰不想持久保存的属性

     作者:ssslinppp       1. 摘要 在默认情况下,持久化类的所有属性会自动映射到数据表的数据列.如果在实际应用中不想持久化保存某些属性,则可以考虑使用@Transient来修饰他们. ...

  5. Celery 异步定时周期任务

    1/什么是Celery Celery 是基于Python实现的模块,用于执行异步定时周期任务的 其结构的组成是由 1.用户任务app 2.管道 broker 用于存储任务 官方推荐 redis rab ...

  6. 服务注册发现consul之五:Consul移除失效服务的正确姿势

    spring cloud微服务不定期会出现网络请求失败的错误.于是看了下后台日志,发现有几个请求会报如下的异常: Caused by: feign.RetryableException: Connec ...

  7. 【转载】深入浅出REST

    英文原文:A Brief Introduction to REST 作者:Stefan Tilkov ,译者:苑永凯,发布于 2007-12-25 不知你是否意识到,围绕着什么才是实现异构的应用到应用 ...

  8. java study2

    Intellj小技巧 数组 1.java数组元素类型是唯一的,即一个数组只能存储一种数据类型的数据,而不能存储多种数据类型的数据. 2.java数组的长度,一旦初始化完成,控件就被固定,即数组的长度将 ...

  9. 尽量少嵌套无用的div;外部文件尽量使用link而不要使用用@import

    最近的工作又学到了很多东西,在这里记录一下. 1,尽量少嵌套无用的div,这个问题领导很严肃的跟我提过很多次,因为我很喜欢用很多div,而且有很多div都是无存在意义的.后来领导给了我一些资料,我看了 ...

  10. PHP中的urlencode,rawurlencode和JS中的encodeURI,encodeURIComponent

    PHP中的urlencode,rawurlencode和JS中的encodeURI,encodeURIComponent [PHP中的urlencode和rawurlencode] urlencode ...