我有一个从A类到B类的总映射。
import qualified Data.Map as M
import Data.Maybe
tmGet k m = fromJust $ M.lookup k m
tmSet k v = M.insert k v
我使用Data.Map
作为示例实现,但它可以是任何内容,例如一个Array
甚至一个Bool
- 索引元组:
tmGet True = fst
tmGet False = snd
我希望有一个tmAt
功能来构建镜头:
(42, 665) ^. tmAt True == 42
(42, 665) & tmAt False +~ 1 == (42, 666)
问题是我如何从tmAt
和tmGet
(或tmSet
)构建tmModify
?
答案 0 :(得分:3)
如果你看the documentation for the Control.Lens module,那么 lens 包的不同部分就会有一个非常方便的图像。由于您要构建Lens
,因此可以查看图表的Lens
部分。显示的最上面的函数是
lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
这构建了一个来自getter和setter的镜头。
函数s -> a
是一个getter - 类型签名意味着,“如果你给我一个数据结构s
,我会从中选择一个a
值。” s -> b -> t
函数是setter,类型签名表示“如果你给我一个s
和一个新值b
,我会为你创建一个新结构{{1} }“。 (类型不同,因为镜头实际上可以改变事物的类型。)
如果您的吸气剂为t
而您的定位器为tmGet
,则可以构建一个带
tmSet
无论您的实际tmAt :: Boolean -> Lens s t a b
tmAt b = lens (tmGet b) (tmSet b)
,s
,t
和a
参数是什么。在元组的例子中,它将是
b
(换句话说,如果你给镜头一个函数tmAt :: Bool -> Lens (a, a) (a, a) a a
,它可以将a -> a
- 元组转换为另一个(a, a)
- 元组。)
如果您想要花哨,您也可以将(a, a)
重写为
tmAt
答案 1 :(得分:0)
将tmGet
和tmSet
定义为
tmGet :: k -> f v -> v
tmSet :: k -> f v -> v -> f v
您可以通过镜头构造函数lens
和参数化的getter和setter来定义一系列镜头。以下是对Bool
tmGet True = fst
tmGet False = snd
tmSet True (_,b) a = (a,b)
tmSet False (a,_) b = (a,b)
tmAt b = lens (tmGet b) (tmSet b)
现在在GHCI
>>> (42,665) ^. tmAt True
42
>>> (42,665) & tmAt False +~ 1
(42,666)