Control.Lens镜头为总地图

时间:2013-10-15 12:43:12

标签: haskell lenses lens

我有一个从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)

问题是我如何从tmAttmGet(或tmSet)构建tmModify

2 个答案:

答案 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) sta参数是什么。在元组的例子中,它将是

b

(换句话说,如果你给镜头一个函数tmAt :: Bool -> Lens (a, a) (a, a) a a ,它可以将a -> a - 元组转换为另一个(a, a) - 元组。)


如果您想要花哨,您也可以将(a, a)重写为

tmAt

答案 1 :(得分:0)

tmGettmSet定义为

类型后
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)