如何为非记录newtype类型生成命名Lens?
两种实现命名Lens的简洁方案
用Lens组合子直接实现
你想的简洁写法思路是对的,只需借助lens库自带的_Wrapped组合子处理newtype的拆包,最终可以写成:
import Control.Lens bar :: Lens' Foo Int bar = _Wrapped . _1
_Wrapped是Wrapped类型类提供的Lens,专门用来访问newtype包裹的内部值,和元组的_1组合后,就直接实现了访问Foo内部元组第一个元素的Lens,完全不用手动写lens函数的getter和setter。
如果要访问第二个元素的String,同理可以写:
baz :: Lens' Foo String baz = _Wrapped . _2
用Template Haskell自动生成
如果想进一步自动化,甚至不用自己写组合代码,可以用lens库的Template Haskell功能:
- 先启用Template Haskell扩展,在文件顶部添加:
{-# LANGUAGE TemplateHaskell #-}
- 导入TH相关模块:
import Control.Lens.TH
- 给你的
Foo类型自动生成_WrappedLens:
newtype Foo = Foo (Int, String) makeWrapped ''Foo
执行这行TH代码后,会自动生成_Wrapped :: Lens' Foo (Int, String),之后你还是可以像之前一样用_Wrapped . _1定义bar。
另外,如果你愿意把newtype改成记录语法,还能让TH直接生成对应内部结构的基础Lens:
newtype Foo = Foo { unFoo :: (Int, String) } makeLenses ''Foo
这样会生成unFoo :: Lens' Foo (Int, String),同样可以和_1组合得到bar,这属于记录式newtype的用法,可根据需求选择。
内容的提问来源于stack exchange,提问作者majkrzak
相关产品推荐
相关产品推荐

